代码之家  ›  专栏  ›  技术社区  ›  sbi

如何使循环体在C中并行运行#

  •  2
  • sbi  · 技术社区  · 15 年前

    我有一个这样的环

    ICollection<Data> GetData()
    {
      ICollection<Data> result = new List<Data>()
      foreach (var item in aCollection)
        item.AddData(result);
      return result;
    }
    

    我现在需要并行执行,而不是迭代执行。我的第一次尝试是这样做

    ICollection<Data> GetData()
    {
      ICollection<Data> result = new SynchronizedCollection<Data>()
      foreach (var item in aCollection)
        new Thread(delegate() { item.AddData(result); }).Start();
      return result;
    }
    

    但在返回结果之前,我需要一种方法来等待所有要添加的数据。

    最简单的方法是什么?

    编辑: AddData 将通过网络呼叫。在收藏中通常有多达几十个条目。

    5 回复  |  直到 15 年前
        1
  •  2
  •   Oliver Hanappi    15 年前

    您可以使用C 4.0中集成的并行扩展,C 3.5作为单独的库提供,您可以在此处下载: Microsoft Parallel Extensions to .NET Framework 3.5 .

    如果不想使用并行扩展,不要每次迭代都启动一个线程,而是使用threadpool,这样可以获得更好的性能。

    正如我在这个答案的评论中所知道的,list<>不是线程安全的,为什么您应该使用synchronizedCollection<>。

    下面是一个使用线程池的代码示例。

            IEnumerable<object> providers = null;
    
            var waitHandles = new List<WaitHandle>();
            foreach (var provider in providers)
            {
                var resetEvent = new ManualResetEvent(false);
                waitHandles.Add(resetEvent);
    
                ThreadPool.QueueUserWorkItem(s =>
                 {
                     // do whatever you want.
                     ((EventWaitHandle)s).Set();
                 }, resetEvent);
            }
    
            WaitHandle.WaitAll(waitHandles.ToArray());
    
        2
  •  2
  •   Brian Rasmussen    15 年前

    除非adddata真的很慢,否则创建新线程的开销很可能是代码中的瓶颈。

    如果你想把这个交给其他线程,你应该使用threadpool来完成这个任务。至于等待线程完成,可以使用等待句柄在线程之间发出信号。

        3
  •  1
  •   Razzie    15 年前

    在C 4.0中,您可以使用如下内容:

    Parallel.ForEach<Data>(aCollection, delegate(Data d)
    {
      d.AddData(result);
    });
    
        4
  •  0
  •   flq    15 年前

    最简单的方法可能是等待Parallels框架进入4.0版本。

    好吧,对于初学者,您需要注意线程的创建。如果你有几百甚至数千个项目,那么这些代码可能会杀死你的应用程序,或者至少会扼杀你的性能。

    我会尝试设计 附加数据 方法作为异步调用。这个 综合结果 有一个waithandle。您可以等待这些句柄,直到所有AsyncResults状态都表明操作已完成。然后你可以继续。异步执行这些操作应该确保使用线程池中的线程。这样,您就获得了相当好的性能,并且如果您的列表变得非常大,您就可以达到工作线程的自然饱和。

        5
  •  -1
  •   Blindy    15 年前

    存储对您创建的线程对象的引用,并对每个线程对象调用join:

    ICollection<Data> GetData()
    {
      ICollection<Data> result = new SynchronizedCollection<Data>()
      List<Thread> threads=new List<Thread>();
    
      foreach (var item in aCollection)
      {
        Thread thread=new Thread(delegate() { item.AddData(result); });
        thread.Start();
        threads.Add(thread);
      }
    
      foreach(Thread thread in threads)
        thread.Join();
    
      return result;
    }