我正在尝试对列表A中的每个元素X进行比较,如果X的两个属性X.Code和X.Rate具有匹配ListB中任何元素Y的Code和Rate。当前的解决方案使用LINQ和AsParallel来执行这些比较(时间是一个因素,每个列表可以包含从0个元素到每个数百个元素的任意位置)。
到目前为止,AsParallel方法似乎要快得多,但是我不确定这些操作是否是线程安全的。我的理解是,因为这种比较只会读取值,而不会修改它们,所以这应该是安全的,但我不是100%自信。在将其释放到生产环境之前,如何确定该操作是否是线程安全的?
这是我正在使用的代码:
var s1 = System.Diagnostics.Stopwatch.StartNew();
ListA.AsParallel().ForAll(x => x.IsMatching = ListB.AsParallel().Any(y => x.Code== y.Code && x.Rate== y.Rate));
s1.Stop();
var s2 = System.Diagnostics.Stopwatch.StartNew();
ListA.ForEach(x => x.IsMatching = ListB.Any(y => x.Code == y.Code && x.Rate== y.Rate));
s2.Stop();
当前,每种方法都返回相同的结果,但是AsParallel()的执行时间是普通ForEach的1/3,因此,如果有一种可以安全地执行此操作的方法,我希望可以从中受益。
最佳答案
您拥有的代码是线程安全的。列表以只读方式访问,实现并行化版本所需的隐式同步足以确保已落实任何写入。您确实修改了列表中的元素,但是同样,并行操作中隐含的同步(当前线程必须等待该同步)将确保对元素对象的任何写入在当前线程中可见。
就是说,线程安全是无关紧要的,因为您做的整个事情都是错误的。您正在将O(N ^ 2)蛮力算法应用到可以使用更优雅,更有效的解决方案LINQ join
来解决的需求:
var join = from x in list1
join y in list2 on new { x.Code, x.Rate } equals new { y.Code, y.Rate }
select x;
foreach (A a in join)
{
a.IsMatching = true;
}
您的代码示例未包含示例数据的任何初始化。因此,我无法可靠地复制您的结果。确实,在我的测试集中,我以相同的方式初始化了
list1
和list2
,并且每个元素都具有相同的1000个元素(我只是将Code
和Rate
设置为列表中元素的索引,即0
通过999
),我发现AsParallel()
版本的运行速度比串行版本要多出25%(即并行版本的250次迭代花费了大约2.7秒,而串行版本的250次迭代花费了大约1.9秒)。但是,两者都不接近
join
版本,后者在大约60毫秒内完成了该特定测试数据的250次迭代,几乎比其他两种实现的速度快20倍。我有足够的信心,尽管我缺乏与您的方案相关的可比数据集,但基本结果仍然有效,并且您会发现
join
方法的使用远胜于您选择的任何一种方法到目前为止尝试过。关于c# - 是否可以确定列表操作是否是线程安全的?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28025973/