C# - 用于服务调用的 Parallel.Foreach()

Posted

技术标签:

【中文标题】C# - 用于服务调用的 Parallel.Foreach()【英文标题】:C# - Parallel.Foreach() for Service Call 【发布时间】:2020-09-05 17:15:39 【问题描述】:

我有一个控制台应用程序,它执行下面提到的 3 个步骤,

    从 db 获取待处理的通知记录 调用服务发送电子邮件(服务返回电子邮件地址作为响应) 得到服务响应后,更新数据库

对于第 2 步,我使用的是 Parallel.Foreach(),它的效果比 foreach() 好得多。 我已经阅读了很多关于 *** 的文章和线程,这在这个主题上造成了更多的混乱。 我有几个问题

    我在服务器上运行它,它会影响性能吗?我应该限制线程数吗? (电子邮件数量可以是 0-500 或 1000) 我遇到了一个问题,在第 2 步中,服务返回了一个电子邮件地址作为响应,但在更新数据库时它不可用。 (这里的电子邮件数量是 400) 我怀疑这个问题可能是因为使用了 parallel.foreach 并且它没有添加到 notifList 中。 如果是这种情况,我可以在 Parallel.Foreach() 循环结束后添加 Thread.Sleep(1000),是否可以解决问题? 万一出现异常,我应该明确取消线程吗?

感谢您花时间和精力帮助我。谢谢!

public void notificationMethod()

    List<notify> notifList = new List<notify>();

    //step 1
    List<orders> orderList = GetNotifs();

    try
    
        if (orderList.Count > 0)
        
            Parallel.ForEach(orderList, (orderItem) =>
            
               //step 2
               SendNotifs(orderItem);
                notifList.Add(new notify()
               
                   //building list by adding email address along with other information
               );
            );
            if (notifList.Count > 0)
            
                int index = 0; 
                int rows = 10; 
                int skipRows = index * rows;
                int updatedRows = 0;
                while (skipRows < notifList.Count)
                
                    //pagination 
                    List<notify> subitem = notifList.Skip(index * rows).Take(rows).ToList<notify>();
                    updatedRows += subitem.Count;

                    //step 3
                    UpdateDatabase(subitem);

                    index++;
                    skipRows = index * rows;
                
            
        
    
    catch (ApplicationException ex)
    
                



【问题讨论】:

我认为您应该使用一种专门的并发集合类型(用于 notifList),而不是 List,我会使用 ConcurrentBag 看看是否能解决问题跨度> 除了@StewartRitchie 评论,我建议您也为此使用任务并行库。该库为您完成大部分线程管理,并且有一些方法可以捕获和处理每个请求的异常。没有直接涉及线程,因此通常使用起来也更安全。然后,您可以使用await foreach() 并行运行这些。 Review the docs here 了解更多详情。 @NikP 如果他们正在使用Parallel.ForEach,他们已经在使用 TPL。您引用的内容是否更具体? @digitlworld 是的,专门将单个调用包装在任务中并使用 TAP 模式,并遵循异常处理建议 here 和 here。要点是更好地控制在何处捕获哪些异常以及如何处理它们,因此如果 1000 个调用中的一个抛出,它不会弄乱其余的,您可以跟踪失败的调用以找出原因。 扩展@StewartRitchie 提到的内容:List&lt;T&gt; 不是线程安全的。如果多个线程同时添加项目,您肯定会丢失一些。 ConcurrentBag&lt;T&gt; 线程安全的。 【参考方案1】:

关于使用Parallel.ForEach() 是否有助于提高性能,我也有类似的情况。但是当我看到下面来自 Microsoft 的视频时,它让我想到了为 CPU 密集型工作负载选择 Parallel.ForEach()only。 在这种情况下,您的场景将属于 I/O 密集型工作负载,async/await 可以更好地处理。

https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Tip-2-Distinguish-CPU-Bound-work-from-IO-bound-work

【讨论】:

以上是关于C# - 用于服务调用的 Parallel.Foreach()的主要内容,如果未能解决你的问题,请参考以下文章

c# 异步编程学习笔记

c# 异步编程学习笔记

c# 异步编程学习笔记

c# 异步编程学习笔记

C#之任务,线程和同步

c# 并发编程系列之三:使用 Parallel 开始第1个多线程编码