我有一组对象需要通过一组规则来运行,以确定这些对象是否符合/匹配给定的规则集合。
最初这是作为Sql Link语句编写的:
来自对象中的x 从规则中的y
我首先将该语句转换为ForEach / inner ForEach语句。 结果输出符合预期结果。
在许多其他情况下使用了Parallel.ForEach,我认为这是一个在这里使用它的好地方。
objects.ForEach(o => {
var obj = o.Value;
var ruleCount = 0;
//eventRules.ForEach(r => {
Parallel.ForEach(eventRules, r => {
var matchedDetail = r.GetMatchDetails(obj, _ruleContext);
var matched = matchedDetail.Matched;
if (matchedDetail.Matched)
{
var result = CreateResult(obj, r, matchedDetail);
matchedResults.Add(result);
}
ruleCount += 1;
});
Console.WriteLine($"{obj.object_id} {eventRules.Count()} {ruleCount}");
});
84052 83 82
35135 83 82
37576 83 83
38772 83 81
80513 83 81
95824 83 83
99402 83 82
24626 83 83
30711 83 82
96613 83 83
63487 83 83
78497 83 83
81404 83 83
93719 83 82
36600 83 83
68544 83 83
78685 83 81
在添加Parallel.ForEach后注意到结果不匹配后,我添加了额外的ruleCount标记和输出。这表明随机我会看到3或4个规则未被运行/返回。将标准ForEach替换回来,会产生一个非常一致但尽管速度较慢的运行。 我对MSDN文档和其他来源的理解表明,Parallel.ForEach应该等到所有操作完成后再返回给调用者。
另外,我用4.5.1测试了这个,而4.6.1都表现出相同的行为。
答案 0 :(得分:3)
执行的某些操作不是线程安全的。
其中一个是ruleCount += 1;
。您可以将其替换为Interlocked.Increment
,以使其成为原子和线程安全的。
Interlocked.Increment(ref ruleCount);
另一个(可能的)是matchedResults.Add(result);
。我无法看到matchedResults
集合的类型,但您应该确保它是thread-safe collection(例如ConcurrentQueue
)。您还可以使用lock
来同步对常规集合的访问,但使用线程安全集合是一个更好的主意。