在C#中使用multithreading加速循环(问题)

想象一下,我有一个function,它通过一百万个/十亿字符串并检查其中的smth。

f.ex:

foreach (String item in ListOfStrings) { result.add(CalculateSmth(item)); } 

它消耗了大量的时间,因为CalculateSmth是非常耗时的function。

我想问一下:如何在这种过程中集成multithreading?

f.ex:我想启动5个线程,每个线程返回一些结果,直到列表中有项目为止。

也许任何人都可以展示一些例子或文章..

忘记提到我需要它在.NET 2.0中

您可以尝试并行扩展 (.NET 4.0的一部分)

这些允许你写这样的东西:

 Parallel.Foreach (ListOfStrings, (item) => result.add(CalculateSmth(item)); ); 

当然result.add需要是线程安全的。

Parallel扩展很酷,但这也可以通过使用如下的线程池完成:

 using System.Collections.Generic; using System.Threading; namespace noocyte.Threading { class CalcState { public CalcState(ManualResetEvent reset, string input) { Reset = reset; Input = input; } public ManualResetEvent Reset { get; private set; } public string Input { get; set; } } class CalculateMT { List result = new List(); List events = new List(); private void Calc() { List aList = new List(); aList.Add("test"); foreach (var item in aList) { CalcState cs = new CalcState(new ManualResetEvent(false), item); events.Add(cs.Reset); ThreadPool.QueueUserWorkItem(new WaitCallback(Calculate), cs); } WaitHandle.WaitAll(events.ToArray()); } private void Calculate(object s) { CalcState cs = s as CalcState; cs.Reset.Set(); result.Add(cs.Input); } } } 

请注意,并发性并不能为您提供更多资源。 你需要建立什么减慢CalculateSmth。

例如,如果它受CPU限制(并且您在单个核心上),则无论是顺序执行还是并行执行,都会将相同数量的CPU标记输入到代码中。 另外,你可以从管理线程中获得一些开销。 相同的参数适用于其他约束(例如I / O)

如果CalculateSmth在执行期间保留资源,那么您只能获得性能提升,这可以被另一个实例使用。 这并不罕见。 例如,如果任务涉及IO后跟一些CPU内容,则进程1可能正在执行CPU内容,而进程2正在执行IO。 正如垫子所指出的那样,如果您拥有基础设施,那么生产者 – 消费者单位链就可以实现这一目标。

您需要并行拆分要执行的工作。 以下是如何将工作分成两部分的示例:

 List work = (some list with lots of strings) // Split the work in two List odd = new List(); List even = new List(); for (int i = 0; i < work.Count; i++) { if (i % 2 == 0) { even.Add(work[i]); } else { odd.Add(work[i]); } } // Set up to worker delegates List oddResult = new List(); Action oddWork = delegate { foreach (string item in odd) oddResult.Add(CalculateSmth(item)); }; List evenResult = new List(); Action evenWork = delegate { foreach (string item in even) evenResult.Add(CalculateSmth(item)); }; // Run two delegates asynchronously IAsyncResult evenHandle = evenWork.BeginInvoke(null, null); IAsyncResult oddHandle = oddWork.BeginInvoke(null, null); // Wait for both to finish evenWork.EndInvoke(evenHandle); oddWork.EndInvoke(oddHandle); // Merge the results from the two jobs List allResults = new List(); allResults.AddRange(oddResult); allResults.AddRange(evenResult); return allResults; 

您必须回答的第一个问题是您是否应该使用线程

如果您的函数CalculateSmth()基本上是CPU限制的,即CPU使用率很高且基本上没有I / O使用,那么我很难看到使用线程的重点,因为线程将在同一资源上竞争,在这种情况下是CPU。

如果您的CalculateSmth()同时使用CPU和I / O,那么它可能是使用线程的一个重点。

我完全同意对我的回答的评论。 我做了一个错误的假设,我们正在讨论一个带有一个内核的CPU,但是现在我们有多核CPU,不好。

并不是说我现在有任何好文章,但你想要做的是使用Threadpool的Producer-Consumer。

生产者循环并创建任务(在这种情况下,可能只是排队列表或堆栈中的项目)。 例如,消费者是五个线程,它们从堆栈中读取一个项目,通过计算消耗它,然后将其存储在其他位置。

这种方式multithreading仅限于这五个线程,并且它们都有工作要做,直到堆栈为空。

需要考虑的事情:

  • 将保护放在输入和输出列表中,例如互斥锁。
  • 如果订单很重要,请确保维护输出订单。 一个例子可以是将它们存储在SortedList或类似的东西中。
  • 确保CalculateSmth是线程安全的,它不使用任何全局状态。