I am trying to speed up the execution for large number of dataset using parallel.
However, I encounter some list/dictionary concurrent add/update issue.
using System;
using System.Collections.Concurrent;
using System.Dynamic;
using System.Linq;
using System.Text.Json;
using net.adamec.lib.common.dmn.engine.engine.decisions;
using net.adamec.lib.common.dmn.engine.engine.runtime;
using net.adamec.lib.common.dmn.engine.parser;
public class Program
{
public static void Main()
{
string DmnXmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><definitions xmlns=\"https://www.omg.org/spec/DMN/20191111/MODEL/\" xmlns:dmndi=\"https://www.omg.org/spec/DMN/20191111/DMNDI/\" xmlns:dc=\"http://www.omg.org/spec/DMN/20180521/DC/\" xmlns:di=\"http://www.omg.org/spec/DMN/20180521/DI/\" id=\"dish\" name=\"Dish\" namespace=\"http://camunda.org/schema/1.0/dmn\" exporter=\"dmn-js (https://demo.bpmn.io/dmn)\" exporterVersion=\"10.1.0\"> <inputData id=\"dayType_id\" name=\"TypeOfDay\"> <variable id=\"dayType_ii\" name=\"Type of day\" typeRef=\"string\" /> </inputData> <inputData id=\"temperature_id\" name=\"WeatherInCelsius\"> <variable id=\"temperature_ii\" name=\"Weather in Celsius\" typeRef=\"integer\" /> </inputData> <knowledgeSource id=\"host_ks\" name=\"Host\" /> <knowledgeSource id=\"guest_ks\" name=\"Guest Type\"> <authorityRequirement id=\"AuthorityRequirement_0vkhray\"> <requiredDecision href=\"#guestCount\" /> </authorityRequirement> </knowledgeSource> <businessKnowledgeModel id=\"elMenu\" name=\"El menú\" /> <decision id=\"dish-decision\" name=\"Dish Decision\"> <informationRequirement id=\"InformationRequirement_1d56kg6\"> <requiredDecision href=\"#guestCount\" /> </informationRequirement> <informationRequirement id=\"InformationRequirement_11onl5b\"> <requiredDecision href=\"#season\" /> </informationRequirement> <authorityRequirement id=\"AuthorityRequirement_142y75e\"> <requiredAuthority href=\"#host_ks\" /> </authorityRequirement> <decisionTable id=\"dishDecisionTable\"> <input id=\"seasonInput\" label=\"Season\"> <inputExpression id=\"seasonInputExpression\" typeRef=\"string\"> <text>season</text> </inputExpression> </input> <input id=\"guestCountInput\" label=\"GuestCount\"> <inputExpression id=\"guestCountInputExpression\" typeRef=\"integer\"> <text></text> </inputExpression> </input> <output id=\"output1\" label=\"Dish\" name=\"desiredDish\" typeRef=\"string\" /> <rule id=\"row-495762709-1\"> <inputEntry id=\"UnaryTests_1nxcsjr\"> <text>\"Winter\"</text> </inputEntry> <inputEntry id=\"UnaryTests_1r9yorj\"> <text><= 8</text> </inputEntry> <outputEntry id=\"LiteralExpression_1mtwzqz\"> <text>\"Spareribs\"</text> </outputEntry> </rule> <rule id=\"row-495762709-2\"> <inputEntry id=\"UnaryTests_1lxjbif\"> <text>\"Winter\"</text> </inputEntry> <inputEntry id=\"UnaryTests_0nhiedb\"> <text>> 8</text> </inputEntry> <outputEntry id=\"LiteralExpression_1h30r12\"> <text>\"Pasta\"</text> </outputEntry> </rule> <rule id=\"row-495762709-3\"> <inputEntry id=\"UnaryTests_0ifgmfm\"> <text>\"Summer\"</text> </inputEntry> <inputEntry id=\"UnaryTests_12cib9m\"> <text>> 10</text> </inputEntry> <outputEntry id=\"LiteralExpression_0wgaegy\"> <text>\"Light salad\"</text> </outputEntry> </rule> <rule id=\"row-495762709-7\"> <inputEntry id=\"UnaryTests_0ozm9s7\"> <text>\"Summer\"</text> </inputEntry> <inputEntry id=\"UnaryTests_0sesgov\"> <text><= 10</text> </inputEntry> <outputEntry id=\"LiteralExpression_1dvc5x3\"> <text>\"Beans salad\"</text> </outputEntry> </rule> <rule id=\"row-445981423-3\"> <inputEntry id=\"UnaryTests_1er0je1\"> <text>\"Spring\"</text> </inputEntry> <inputEntry id=\"UnaryTests_1uzqner\"> <text>< 10</text> </inputEntry> <outputEntry id=\"LiteralExpression_1pxy4g1\"> <text>\"Stew\"</text> </outputEntry> </rule> <rule id=\"row-445981423-4\"> <inputEntry id=\"UnaryTests_06or48g\"> <text>\"Spring\"</text> </inputEntry> <inputEntry id=\"UnaryTests_0wa71sy\"> <text>>= 10</text> </inputEntry> <outputEntry id=\"LiteralExpression_09ggol9\"> <text>\"Steak\"</text> </outputEntry> </rule> </decisionTable> </decision> <decision id=\"season\" name=\"Season decision\"> <informationRequirement id=\"InformationRequirement_1sdwefx\"> <requiredInput href=\"#temperature_id\" /> </informationRequirement> <decisionTable id=\"seasonDecisionTable\"> <input id=\"temperatureInput\" label=\"WeatherInCelsius\"> <inputExpression id=\"temperatureInputExpression\" typeRef=\"integer\"> <text></text> </inputExpression> </input> <output id=\"seasonOutput\" label=\"season\" name=\"season\" typeRef=\"string\" /> <rule id=\"row-495762709-5\"> <inputEntry id=\"UnaryTests_1fd0eqo\"> <text>>30</text> </inputEntry> <outputEntry id=\"LiteralExpression_0l98klb\"> <text>\"Summer\"</text> </outputEntry> </rule> <rule id=\"row-495762709-6\"> <inputEntry id=\"UnaryTests_1nz6at2\"> <text><10</text> </inputEntry> <outputEntry id=\"LiteralExpression_08moy1k\"> <text>\"Winter\"</text> </outputEntry> </rule> <rule id=\"row-445981423-2\"> <inputEntry id=\"UnaryTests_1a0imxy\"> <text>[10..30]</text> </inputEntry> <outputEntry id=\"LiteralExpression_1poftw4\"> <text>\"Spring\"</text> </outputEntry> </rule> </decisionTable> </decision> <decision id=\"guestCount\" name=\"Guest Count\"> <informationRequirement id=\"InformationRequirement_0j60f3j\"> <requiredInput href=\"#dayType_id\" /> </informationRequirement> <knowledgeRequirement id=\"KnowledgeRequirement_0n56cqb\"> <requiredKnowledge href=\"#elMenu\" /> </knowledgeRequirement> <decisionTable id=\"guestCountDecisionTable\"> <input id=\"typeOfDayInput\" label=\"TypeOfDay\"> <inputExpression id=\"typeOfDayInputExpression\" typeRef=\"string\"> <text></text> </inputExpression> </input> <output id=\"guestCountOutput\" label=\"GuestCount\" typeRef=\"integer\" /> <rule id=\"row-495762709-8\"> <inputEntry id=\"UnaryTests_0l72u8n\"> <text>\"Weekday\"</text> </inputEntry> <outputEntry id=\"LiteralExpression_0wuwqaz\"> <text>4</text> </outputEntry> </rule> <rule id=\"row-495762709-9\"> <inputEntry id=\"UnaryTests_03a73o9\"> <text>\"Holiday\"</text> </inputEntry> <outputEntry id=\"LiteralExpression_1whn119\"> <text>10</text> </outputEntry> </rule> <rule id=\"row-495762709-10\"> <inputEntry id=\"UnaryTests_12tygwt\"> <text>\"Weekend\"</text> </inputEntry> <outputEntry id=\"LiteralExpression_1b5k9t8\"> <text>15</text> </outputEntry> </rule> </decisionTable> </decision> <textAnnotation id=\"TextAnnotation_1\"> <text>Week day or week end</text> </textAnnotation> <association id=\"Association_18hoj4i\"> <sourceRef href=\"#dayType_id\" /> <targetRef href=\"#TextAnnotation_1\" /> </association> <dmndi:DMNDI> <dmndi:DMNDiagram id=\"DMNDiagram_05sfxgt\"> <dmndi:DMNShape id=\"DMNShape_1nkrqp5\" dmnElementRef=\"dayType_id\"> <dc:Bounds height=\"45\" width=\"125\" x=\"417\" y=\"377\" /> </dmndi:DMNShape> <dmndi:DMNShape id=\"DMNShape_0wgwr3t\" dmnElementRef=\"temperature_id\"> <dc:Bounds height=\"45\" width=\"125\" x=\"188\" y=\"377\" /> </dmndi:DMNShape> <dmndi:DMNShape id=\"DMNShape_17n98pm\" dmnElementRef=\"host_ks\"> <dc:Bounds height=\"63\" width=\"100\" x=\"646\" y=\"48\" /> </dmndi:DMNShape> <dmndi:DMNShape id=\"DMNShape_1i9incu\" dmnElementRef=\"guest_ks\"> <dc:Bounds height=\"63\" width=\"100\" x=\"660\" y=\"198\" /> </dmndi:DMNShape> <dmndi:DMNEdge id=\"DMNEdge_0tdfvdg\" dmnElementRef=\"AuthorityRequirement_0vkhray\"> <di:waypoint x=\"570\" y=\"245\" /> <di:waypoint x=\"660\" y=\"235\" /> </dmndi:DMNEdge> <dmndi:DMNShape id=\"DMNShape_1uo50vq\" dmnElementRef=\"elMenu\"> <dc:Bounds height=\"46\" width=\"135\" x=\"642\" y=\"307\" /> </dmndi:DMNShape> <dmndi:DMNShape id=\"DMNShape_0s7a8pk\" dmnElementRef=\"dish-decision\"> <dc:Bounds height=\"80\" width=\"180\" x=\"301\" y=\"48\" /> </dmndi:DMNShape> <dmndi:DMNEdge id=\"DMNEdge_1cvfntf\" dmnElementRef=\"InformationRequirement_1d56kg6\"> <di:waypoint x=\"480\" y=\"210\" /> <di:waypoint x=\"421\" y=\"148\" /> <di:waypoint x=\"421\" y=\"128\" /> </dmndi:DMNEdge> <dmndi:DMNEdge id=\"DMNEdge_0djoiii\" dmnElementRef=\"InformationRequirement_11onl5b\"> <di:waypoint x=\"251\" y=\"210\" /> <di:waypoint x=\"361\" y=\"148\" /> <di:waypoint x=\"361\" y=\"128\" /> </dmndi:DMNEdge> <dmndi:DMNEdge id=\"DMNEdge_0qqxexx\" dmnElementRef=\"AuthorityRequirement_142y75e\"> <di:waypoint x=\"646\" y=\"81\" /> <di:waypoint x=\"481\" y=\"86\" /> </dmndi:DMNEdge> <dmndi:DMNShape id=\"DMNShape_06z5z89\" dmnElementRef=\"season\"> <dc:Bounds height=\"80\" width=\"180\" x=\"161\" y=\"210\" /> </dmndi:DMNShape> <dmndi:DMNEdge id=\"DMNEdge_1383eyj\" dmnElementRef=\"InformationRequirement_1sdwefx\"> <di:waypoint x=\"251\" y=\"377\" /> <di:waypoint x=\"251\" y=\"310\" /> <di:waypoint x=\"251\" y=\"290\" /> </dmndi:DMNEdge> <dmndi:DMNShape id=\"DMNShape_0qbhe8q\" dmnElementRef=\"guestCount\"> <dc:Bounds height=\"80\" width=\"180\" x=\"390\" y=\"210\" /> </dmndi:DMNShape> <dmndi:DMNEdge id=\"DMNEdge_131oa1j\" dmnElementRef=\"KnowledgeRequirement_0n56cqb\"> <di:waypoint x=\"691\" y=\"307\" /> <di:waypoint x=\"570\" y=\"262\" /> </dmndi:DMNEdge> <dmndi:DMNEdge id=\"DMNEdge_1avtdb1\" dmnElementRef=\"InformationRequirement_0j60f3j\"> <di:waypoint x=\"480\" y=\"377\" /> <di:waypoint x=\"480\" y=\"310\" /> <di:waypoint x=\"480\" y=\"290\" /> </dmndi:DMNEdge> <dmndi:DMNShape id=\"DMNShape_0bblyhb\" dmnElementRef=\"TextAnnotation_1\"> <dc:Bounds height=\"45\" width=\"125\" x=\"328\" y=\"477\" /> </dmndi:DMNShape> <dmndi:DMNEdge id=\"DMNEdge_0aqnkob\" dmnElementRef=\"Association_18hoj4i\"> <di:waypoint x=\"480\" y=\"422\" /> <di:waypoint x=\"391\" y=\"477\" /> </dmndi:DMNEdge> </dmndi:DMNDiagram> </dmndi:DMNDI></definitions>";
string jsonString = "[{\"TypeOfDay\":\"Holiday\",\"WeatherInCelsius\":24},{\"TypeOfDay\":\"Weekend\",\"WeatherInCelsius\":4}]";
ConcurrentBag<DmnDecisionResult> results = new ConcurrentBag<DmnDecisionResult>();
System.Text.Json.JsonDocument.Parse(jsonString).RootElement
.EnumerateArray()
.AsParallel()
.ForAll(param =>
{
var def = DmnParser.ParseString13(DmnXmlString);
var ctx = DmnExecutionContextFactory.CreateExecutionContext(def);
foreach (var property in System.Text.Json.JsonDocument.Parse(param.GetRawText()).RootElement.EnumerateObject())
{
dynamic propertyvalue = getPropertyValue(property.Value);
ctx.WithInputParameter(property.Name.Trim().Replace(' ', '_'), propertyvalue);
}
var result = ctx.ExecuteDecision("Dish Decision");
results.Add(result);
});
Console.WriteLine(JsonSerializer.Serialize(results.ToList()));
}
private static dynamic getPropertyValue(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.Null:
return null;
case JsonValueKind.Number:
if (element.GetRawText().Contains("."))
return element.GetDouble();
else
return element.GetInt32();
case JsonValueKind.False:
return false;
case JsonValueKind.True:
return true;
case JsonValueKind.Undefined:
return null;
case JsonValueKind.String:
return element.GetString();
case JsonValueKind.Object:
return Newtonsoft.Json.JsonConvert.DeserializeObject<ExpandoObject>(element.GetRawText(), new Newtonsoft.Json.Converters.ExpandoObjectConverter());
//case JsonValueKind.Array:
// result = srcData.EnumerateArray()
// .Select(o => new ReflectionDynamicObject { RealObject = o })
// .ToArray();
// break;
default:
return null;
}
}
}
System.InvalidOperationException: 'Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.'