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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8815147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:35:00  来源:igfitidea点击:

run a method multiple times simultaneously in c#

c#.netmultithreading

提问by ikel

I have a method that returns XML elements, but that method takes some time to finish and return a value.

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

What I have now is

我现在拥有的是

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

but this only runs the next statement after previous one finishes. How can I make it run simultaneously?

但这只会在上一条语句完成后运行下一条语句。我怎样才能让它同时运行?

采纳答案by ?yvind Br?then

You should be able to use tasks for this:

您应该能够为此使用任务:

//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);
}

EDITThere are some problems with the code above. See the code below for a working version. Here I have also rewritten the loops to use LINQ for readability issues (and in the case of the first loop, to avoid the closure on tinside the lambda expression causing problems).

编辑上面的代码有一些问题。有关工作版本,请参阅下面的代码。在这里,我还重写了循环以使用 LINQ 解决可读性问题(在第一个循环的情况下,避免tlambda 表达式内部的闭包导致问题)。

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();

回答by Anders Abel

You can use Parallel.ForEachwhich will utilize multiple threads to do the execution in parallel. You have to make sure that all code called is thread safe and can be executed in parallel.

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

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

回答by Tudor

From what I'm seeing you are updating a shared collection inside the loop. This means that if you execute the loop in parallel a data race will occur because multiple threads will try to update a non-synchronized collection (assuming ris a Listor something like this) at the same time, causing an inconsistent state.

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

To execute correctly in parallel, you will need to wrap that section of code inside a lock statement:

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

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

However, this will make the execution actually serial, because each thread needs to acquire the lock and two threads cannot do so at the same time.

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

The better solution would be to have a local list for each thread, add the partial results to that list and then merge the results when all threads have finished. Probably @?yvind Knobloch-Br?then's second solution is the best one, assuming method(t)is the real CPU-hog in this case.

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

回答by Rama Krshna Ila

Modification to the correct answer for this question change

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

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

to

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