我想学习在Parallel.ForEach
中使用锁定的最佳方法。我应该在整个迭代过程中锁定整个代码块,还是只在执行任何处理之前锁定要用作多线程安全对象?
例如:
Parallel.ForEach(list, item =>
{
lock (secondList)
{
//consider other processes works in here
if (item.Active)
secondList.Add(item);
}
});
或
Parallel.ForEach(list, item =>
{
//consider other processes works in here
if (item.Active)
{
lock (secondList)
secondList.Add(item);
}
});
答案 0 :(得分:2)
如果您的应用程序是并发的(并行性是并发类型之一),并且您想使用线程安全的集合,则没有理由自己锁定集合。 Microsoft提供的一堆并发集合存在于System.Collections.Concurrent中 Thread-safe Collections
答案 1 :(得分:2)
Parallel.ForEach
是一种尝试使代码具有更多并行性的方法。 lock
倾向于在代码 1 中减少并行性。因此,要合并它们 2 。
与Olegl suggested一样,并发回收可能是避免lock
的一种方式。
另一种有趣的方法是在此处使用PLINQ而不是Parallel.ForEach
。已经是2019年了,编写另一个循环的有趣之处是什么?
这将改为执行以下操作:
secondList.AddRange(list.AsParallel.Where(item =>
{
//consider other processes works in here
return item.Active;
});
这使您可以保留非线程安全的secondList
集合,但仍然不必担心锁-因为这是您自己现有的调用AddRange
的线程,最终消耗了IEnumerable<T>
PLINQ提供;因此只有一个线程将项目添加到集合中。
PLINQ尝试调整缓冲选项,但可能无法完成足够好的工作,具体取决于输入list
的大小以及它选择使用多少个线程。如果您不满意由此带来的任何加速(或无法实现任何目的),请在注销之前尝试使用其提供的WithXxx
方法。
如果我必须在您的两个示例之间进行选择(假设它们都是正确的),那么我会选择选项2,因为它在 less 起作用的同时持有其他所有工人都在激烈争夺的锁。
1 除非您知道将被请求的所有锁都具有足够的细粒度,以至没有两个并行线程会尝试获取同一锁。但是如果我们知道,为什么还要再次使用锁?
2 因此,我将四肢伸张地说,当所有并行锁都在同一锁对象上时,将它们组合在一起总是“不正确的”,除非 在lock
之外并行进行着大量处理。
答案 2 :(得分:0)
例如这种用法:
public static T CastTo<T>(this ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] item)
{
var obj = Activator.CreateInstance(typeof(T), true);
var padlock = new object();
Parallel.ForEach(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), prop =>
{
lock (padlock)
{
if (!prop.TryGetAttribute<GldnhrnFieldAttribute>(out var fieldAttribute))
return;
var code = fieldAttribute?.Code;
if (string.IsNullOrEmpty(code)) return;
SetPropertyValue(item, obj, prop);
}
});
return (T)obj;
}
如您所见,我想将数据投射到此处进行分类。使用不同代码块的相同问题,我应该锁定所有代码块还是仅在调用SetPropertyValue方法之前锁定?
public static T CastTo<T>(this ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] item)
{
var obj = Activator.CreateInstance(typeof(T), true);
var padlock = new object();
Parallel.ForEach(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), prop =>
{
if (!prop.TryGetAttribute<GldnhrnFieldAttribute>(out var fieldAttribute))
return;
var code = fieldAttribute?.Code;
if (string.IsNullOrEmpty(code)) return;
lock (padlock)
SetPropertyValue(item, obj, prop);
});
return (T)obj;
}