【问题标题】:Process items in list<Object> by a set of threads - threadpooling通过一组线程处理 list<Object> 中的项目 - 线程池
【发布时间】:2020-12-06 15:46:48
【问题描述】:
public void multithread()
{

  List<Bbject> objectlist= new List<Object>{
      //consider it has around 10 objects
   };
  foreach (var obj in objectlist)
  {               
      Process(obj);
   }
}

private void process(Object obj)
{
    //Implementation
}

我正在尝试实现多线程,其中每个线程获取一个对象并对其进行处理...我尝试创建 5 个单独的线程,每个线程处理 2 个对象...但它更像是硬控制...有什么办法可以使用线程池实现它...

【问题讨论】:

  • 使用 PLinq objectlist.AsParallel().ForAll(o =&gt; {/*your stuff*/}); 或并行类 Parallel.ForEach(objectlist, o=&gt; {/*your stuff*/})。 An,d 对于更复杂的场景,您可以使用 TPL 数据流库
  • Process 方法的工作负载是什么?是CPU-bound or I/O-bound吗?
  • @TheodorZoulias CPU 绑定
  • 对于 CPU 密集型工作负载,.Net 平台提供的最容易使用的工具是 Parallel 类和并行 LINQ (PLINQ)。

标签: c# .net multithreading asp.net-core asp.net-web-api


【解决方案1】:

我会避免手动创建Thread 对象。现代 .NET 提供了更强大的工具来处理并发。根据经验,每次您在现代 .NET 中编写 new Thread 之类的代码时,您几乎肯定没有在做正确的事情。

似乎最适合您的问题的解决方案是在 Parallel 类上定义的静态方法 ForEach

Parallel.ForEach 基本上将在提供的对象序列上运行并行foreach 循环。用于并行处理项目的线程是从.NET框架直接管理的线程池中借用的,因此您不需要自己创建Thread对象。

在继续之前,您需要考虑一些注意事项:

  • 提供的序列中的项目必须是独立的,以便并行处理它们是安全的操作
  • 当处理所提供序列的每个项目的工作负载受 CPU 限制时,使用 Parallel.ForEach 是有意义的。对于 I/O 工作负载,方法必须不同(在这种情况下,您可以使用 Task.WhenAll 例如)
  • 数据并行性不是免费提供的,进行并行处理总是有计算成本。 因此您需要考虑权衡并始终衡量代码的性能。一般来说,当处理每个项目的工作不是微不足道的并且您在多核处理器上运行代码时,数据并行性是有益的。在某些情况下,经典的顺序 foreach 循环完全有可能带来更好的性能。

也就是说,这是一个代码示例:

public static class Program 
{
  public static void Main(string[] args) 
  {
    List<object> items = ... // code omitted for brevity

    ProcessItemsInParallel(items);
  }

  private static void ProcessItemsInParallel(IEnumerable<object> items) 
  {
    Parallel.ForEach(items, ProcessItem);
  }
   
  private static void ProcessItem(object item) 
  {
    // some non - trivial CPU bound work is done here...
  }
}

这种方法称为数据并行。考虑阅读Parallel.ForEach 的文档。

这里有一些关于 .NET 并发主题的精彩读物:

  • Threading in C# Joseph Albahari 是一本免费的电子书。这本书有点老,但为了获得基础知识,值得一读。这仍然是一本很棒的读物。
  • Stephen Cleary book 关于 C# 中的并发性。在我看来,如果您是 .NET 开发人员并且想要学习处理并发的现代模式,那么这本书是您需要阅读的书。
  • Stephen Cleary blog 是另一个很棒的资源,里面有很多有用和有趣的文章。

最后的考虑。

我注意到您在问题中使用了 ASP.NET 核心标签。您没有提及您尝试在哪里执行繁重的 CPU 密集型处理。

如果您正在考虑在处理 HTTP 请求的上下文中进行这种处理(我的意思是在某个控制器的操作方法中),我强烈建议您不要这样做。这样做会破坏服务器的可扩展性。

应在后端服务中执行大量 CPU 密集型处理; HTTP 请求旨在快速提供服务。

通过保持服务器的可扩展性,可以更轻松地在服务 HTTP 请求的上下文中处理 I/O 绑定工作负载。您可以使用异步操作方法来做到这一点。这并不能保证单个 HTTP 请求将得到快速处理(这取决于您将要执行的 I/O 工作的类型),但至少可以节省服务器的可伸缩性。

但请不要在处理 HTTP 请求时运行并行 foreach 循环。改为使用队列将工作负载从 Web 服务器转发到后端服务。

【讨论】:

    猜你喜欢
    • 2018-07-19
    • 1970-01-01
    • 2011-11-03
    • 2015-03-23
    • 2012-03-31
    • 2020-08-31
    • 2021-08-28
    • 1970-01-01
    • 2015-02-19
    相关资源
    最近更新 更多