为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
婷婷同学_ 2022-07-23 09:25:20
我想学习使用锁定在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);            }        });
查看完整描述

3 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

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


查看完整回答
反对 回复 2022-07-23
?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

Parallel.ForEach是一种尝试在代码中获得更多并行性的方法。lock倾向于降低代码中的并行性1。因此,想要将它们结合起来很少是正确的2。


正如Olegl 所建议的那样,并发集合可能是避免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,因为它在持有所有其他工人激烈争夺的锁时工作较少。


1除非您知道将请求的所有锁都足够细粒度,以至于没有两个并行线程会尝试获取相同的锁。但如果我们知道这一点,我们为什么还要使用锁呢?


2所以我会说,当所有并行锁都在同一个锁对象上时,将它们组合起来“总是”不正确,除非在lock.


查看完整回答
反对 回复 2022-07-23
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

例如那种用途:


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;

    }


查看完整回答
反对 回复 2022-07-23
  • 3 回答
  • 0 关注
  • 302 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号