在c#中多次同时运行一个方法
我有一个返回XML元素的方法,但该方法需要一些时间来完成并返回一个值。
我现在拥有的是什么
foreach (var t in s) { r.add(method(test)); }
但这只会在上一个完成之后运行下一个语句。 如何让它同时运行?
您应该可以使用此任务:
//first start a task for each element in s, and add the tasks to the tasks collection var tasks = new List(); 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.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();
您可以使用Parallel.ForEach
,它将利用多个线程并行执行。 您必须确保所有调用的代码都是线程安全的,并且可以并行执行。
Parallel.ForEach(s, t => r.add(method(t));
从我看到你正在更新循环内的共享集合。 这意味着如果并行执行循环,将发生数据争用,因为多个线程将同时尝试更新非同步集合(假设r
是List
或类似的东西),从而导致状态不一致。
要并行正确执行,您需要将该部分代码包装在lock语句中:
object locker = new object(); Parallel.Foreach (s, t => { lock(locker) r.add(method(t)); });
但是,这将使执行实际上是串行的,因为每个线程需要获取锁,而两个线程不能同时执行。
更好的解决方案是为每个线程创建一个本地列表,将部分结果添加到该列表,然后在所有线程完成后合并结果。 可能@@yvind Knobloch-Bråthen的第二个解决方案是最好的解决方案,假设在这种情况下method(t)
是真正的CPU-hog。
修改此问题更改的正确答案
tasks.Add(Task.Factory.StartNew(method(t);));
至
//solution will be the following code tasks.Add(Task.Factory.StartNew(() => { method(t);}));