在c#中多次同时运行一个方法

时间:2012-01-11 06:37:56

标签: c# .net multithreading

我有一个返回XML元素的方法,但该方法需要一些时间才能完成并返回一个值。

我现在拥有的是

foreach (var t in s)
{
    r.add(method(test));
}

但这仅在前一个语句结束后运行下一个语句。如何让它同时运行?

4 个答案:

答案 0 :(得分:7)

您应该可以使用此任务:

//first start a task for each element in s, and add the tasks to the tasks collection
var tasks = new List<Task>();
foreach( var t in s)
{
    tasks.Add(Task.Factory.StartNew(method(t)));
}

//then wait for all tasks to complete asyncronously
Task.WaitAll(tasks);

//then add the result of all the tasks to r in a treadsafe fashion
foreach( var task in tasks)
{
  r.Add(task.Result);
}

修改 上面的代码存在一些问题。有关工作版本,请参阅以下代码。在这里,我还重写了循环,以便将LINQ用于可读性问题(在第一个循环的情况下,避免在lambda表达式中t上的闭包导致问题)。

var tasks = s.Select(t => Task<int>.Factory.StartNew(() => method(t))).ToArray();

//then wait for all tasks to complete asyncronously
Task.WaitAll(tasks);

//then add the result of all the tasks to r in a treadsafe fashion
r = tasks.Select(task => task.Result).ToList();

答案 1 :(得分:6)

您可以使用Parallel.ForEach来利用多个线程并行执行。您必须确保所有被调用的代码都是线程安全的,并且可以并行执行。

Parallel.ForEach(s, t => r.add(method(t));

答案 2 :(得分:0)

从我看到你正在更新循环内的共享集合。这意味着如果并行执行循环,将发生数据争用,因为多个线程将同时尝试更新非同步集合(假设rList或类似的东西) ,导致状态不一致。

要并行正确执行,您需要将该部分代码包装在lock语句中:

object locker = new object();
Parallel.Foreach (s, 
   t => 
   {  
      lock(locker) r.add(method(t));
   });

但是,这会使执行实际上是串行的,因为每个线程都需要获取锁,而且两个线程不能同时执行。

更好的解决方案是为每个线程创建一个本地列表,将部分结果添加到该列表,然后在所有线程完成后合并结果。可能@@yvind Knobloch-Bråthen的第二个解决方案是最好的解决方案,假设在这种情况下method(t)是真正的CPU-hog。

答案 3 :(得分:0)

修改此问题的正确答案 改变

tasks.Add(Task.Factory.StartNew(method(t);));

//solution will be the following code
tasks.Add(Task.Factory.StartNew(() => { method(t);}));