ThreadPool.QueueUserWorkItem 和 Parallel.ForEach 的区别?

Posted

技术标签:

【中文标题】ThreadPool.QueueUserWorkItem 和 Parallel.ForEach 的区别?【英文标题】:Difference between ThreadPool.QueueUserWorkItem and Parallel.ForEach? 【发布时间】:2013-02-13 21:21:03 【问题描述】:

以下两种方法的主要区别是什么:

ThreadPool.QueueUserWorkItem

    Clients objClient = new Clients();
    List<Clients> objClientList = Clients.GetClientList();

    foreach (var list in objClientList)
    
        ThreadPool.QueueUserWorkItem(new WaitCallback(SendFilesToClient), list);
     

System.Threading.Tasks.Parallel ForEach

    Clients objClient = new Clients();
    List<Clients> objClientList = Clients.GetClientList();

    Parallel.ForEach<Clients>(objClientList, list =>
    
        SendFilesToClient(list);
    );

我是多线程的新手,想知道每种情况下会发生什么(就执行过程而言)每种方法的多线程级别是多少?帮助我可视化这两个过程。

SendFilesToClient: 从数据库中获取数据,转换为 Excel 并将 Excel 文件发送到相应的客户端。

谢谢!

【问题讨论】:

【参考方案1】:

主要区别在于功能。 Parallel.ForEach 将阻塞(按设计),因此在处理完所有对象之前它不会返回。您的foreach 排队线程池线程工作会将工作推送到后台线程,而不是阻塞。

此外,Parallel.ForEach 版本还有另一个主要优点 - 未处理的异常将被推回此处的调用站点,而不是在 ThreadPool 线程上未处理。

一般来说,Parallel.ForEach 会更有效率。这两个选项都使用 ThreadPool,但Parallel.ForEach 执行智能分区以防止线程过多并减少调度程序所需的开销。单个任务(将映射到 ThreadPool 线程)被重用,并有效地“池化”以降低开销,特别是如果 SendFilesToClient 是一个快速操作(在这种情况下不会是真的)。​​

请注意,作为第三种选择,您还可以使用 PLINQ:

objClientList.AsParallel().ForAll(SendFilesToClient);

这在性能和功能方面与Parallel.ForEach 方法非常相似。

【讨论】:

感谢@Reed 的详细解释。两个问题:1)为什么块很重要(如果您能回答我的代码,那就太好了)? 2) 进一步扩展主要问题,使用 PLINQ 而不是 Parallel.ForEach 有什么额外的好处吗? @Mihir 1) 阻塞是不同的。您正在运行的线程将等待 Parallel.ForEach 在运行下一行代码之前完成,但 foreach/TP.QUWI 代码不会等待。 2)没有优势,除了可能更容易理解的代码

以上是关于ThreadPool.QueueUserWorkItem 和 Parallel.ForEach 的区别?的主要内容,如果未能解决你的问题,请参考以下文章