猿问

在 Parallel.ForEach 中使用锁定的正确方法是什么?

我想学习使用锁定在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);

            }

        });


婷婷同学_
浏览 304回答 3
3回答

慕斯王

如果您的应用程序并发(并行性是并发类型之一)并且您想使用线程安全的集合,则没有理由自己锁定集合。微软提供了一堆并发集合,它们存在于 System.Collections.Concurrent Thread-safe Collections

肥皂起泡泡

Parallel.ForEach是一种尝试在代码中获得更多并行性的方法。lock倾向于降低代码中的并行性1。因此,想要将它们结合起来很少是正确的2。正如Olegl 所建议的那样,并发集合可能是避免lock.另一种有趣的方法是在这里使用PLINQ而不是Parallel.ForEach. 已经是 2019 年了,再写一个循环有什么好玩的?这会做这样的事情:secondList.AddRange(list.AsParallel.Where(item =>{&nbsp; &nbsp; //consider other processes works in here&nbsp; &nbsp; return item.Active;});这使您可以保留非线程安全的secondList集合,但仍然不必担心锁——因为AddRange最终消耗IEnumerable<T>PLINQ 提供的是您自己现有的线程调用;所以只有一个线程将项目添加到集合中。PLINQ 尝试调整缓冲选项,但可能无法完成足够好的工作,具体取决于输入的大小list和它选择使用的线程数。如果您对它的任何加速不满意(或者它没有实现任何加速),请WithXxx在注销之前尝试使用它提供的方法。如果我必须在您的两个示例之间进行选择(假设它们在其他方面都是正确的),我会选择选项 2,因为它在持有所有其他工人激烈争夺的锁时工作较少。1除非您知道将请求的所有锁都足够细粒度,以至于没有两个并行线程会尝试获取相同的锁。但如果我们知道这一点,我们为什么还要使用锁呢?2所以我会说,当所有并行锁都在同一个锁对象上时,将它们组合起来“总是”不正确,除非在lock.

qq_花开花谢_0

例如那种用途:public static T CastTo<T>(this ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] item)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var obj = Activator.CreateInstance(typeof(T), true);&nbsp; &nbsp; &nbsp; &nbsp; var padlock = new object();&nbsp; &nbsp; &nbsp; &nbsp; Parallel.ForEach(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), prop =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock (padlock)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!prop.TryGetAttribute<GldnhrnFieldAttribute>(out var fieldAttribute))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var code = fieldAttribute?.Code;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (string.IsNullOrEmpty(code)) return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetPropertyValue(item, obj, prop);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; return (T)obj;&nbsp; &nbsp; }如您所见,我想在这里将我的数据转换为类。不同代码块的相同问题,我应该锁定所有代码块还是应该只在调用 SetPropertyValue 方法之前锁定?&nbsp;public static T CastTo<T>(this ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] item)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var obj = Activator.CreateInstance(typeof(T), true);&nbsp; &nbsp; &nbsp; &nbsp; var padlock = new object();&nbsp; &nbsp; &nbsp; &nbsp; Parallel.ForEach(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), prop =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!prop.TryGetAttribute<GldnhrnFieldAttribute>(out var fieldAttribute))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var code = fieldAttribute?.Code;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (string.IsNullOrEmpty(code)) return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock (padlock)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetPropertyValue(item, obj, prop);&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; return (T)obj;&nbsp; &nbsp; }
随时随地看视频慕课网APP
我要回答