在C#中并行运行三个方法的最简单方法

89

我有三种方法来进行一些数字处理,这些方法如下:

results.LeftFront.CalcAi();  
results.RightFront.CalcAi();  
results.RearSuspension.CalcAi(geom, vehDef.Geometry.LTa.TaStiffness, vehDef.Geometry.RTa.TaStiffness);

这些函数中的每一个都是彼此独立的,且可以并行计算而不会死锁。
有什么最简单的方法可以在所有三个函数完成之前,使包含这些函数的方法也同时完成?


你只对任务并行库的解决方案感兴趣吗?那普通的Delegate.BeginInvoke()甚至Thread.Start()呢? - sll
他想要等待所有的结果 - 你可以用你建议的方法做到这一点,但必须自己进行同步 - 在我看来,除非有非常好的理由不这样做,否则你应该使用Task - 如果C# / async上线,这将变得更加重要。 - Random Dev
我找到的所有线程启动示例都不会等待函数组完成。 - PlTaylor
1
不,他们不会这样做,你应该真正使用Task-Library来处理这种情况。在我看来,微软正在通过async推动这种方法,这确实是一个很好的库(几乎和F#的async-workflows一样好:D)。 - Random Dev
5个回答

151

查看TPL文档。他们列出了这个示例:

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());

因此,在您的情况下,这应该可以正常工作:

Parallel.Invoke(
    () => results.LeftFront.CalcAi(),
    () => results.RightFront.CalcAi(),
    () => results.RearSuspension.CalcAi(geom, 
                                        vehDef.Geometry.LTa.TaStiffness, 
                                        vehDef.Geometry.RTa.TaStiffness));

编辑:调用在所有操作执行完后返回。Invoke()不能保证它们确实并行运行,也不能保证操作执行的顺序。


5
等待直到所有并行任务完成吗? - Jonathan
2
在我所做的所有搜索中,似乎大多数人都忽略了这个简单的例子。感谢您的快速回复和出色的答案。 - PlTaylor
5
@Jonathan,它会等待。该结构类似于启动多个任务,然后调用Task.WaitAll - Libor
1
如何从不同的方法中获取返回值 - F11
这里似乎是一个聪明的方法:https://social.msdn.microsoft.com/Forums/vstudio/en-US/95b7b466-ee41-4a95-a1b5-c4d5b5bc1198/how-do-i-get-the-result-from-parallelinvoke-method?forum=parallelextensions - Anytoe

29

你也可以使用任务来完成这个操作(如果以后需要取消或类似结果,使用任务更好)

var task1 = Task.Factory.StartNew(() => results.LeftFront.CalcAi());
var task2 = Task.Factory.StartNew(() => results.RightFront.CalcAi());
var task3 = Task.Factory.StartNew(() =>results.RearSuspension.CalcAi(geom, 
                              vehDef.Geometry.LTa.TaStiffness, 
                              vehDef.Geometry.RTa.TaStiffness));

Task.WaitAll(task1, task2, task3);

9
使用StartNew可能不是一个好主意,请参见:(http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html) - Microsoft Developer
5
@dotNETNinja 现在情况已经改变 - 正如你所看到的,这个回答已经过时了 - 那时没有异步操作 - 但是无论如何,你可以按照提供的链接建议,将其替换为 Task.Run - 假设你可以使用 .net4.5(或更高版本)。 - Random Dev
我这里有类似的东西.. http://stackoverflow.com/questions/30261335/call-methods-parallel-and-combine-results - Ziggler

3

2
为了运行彼此独立的并行方法,可以使用ThreadPool.QueueUserWorkItem。以下是示例方法-
public static void ExecuteParallel(params Action[] tasks)
{
    // Initialize the reset events to keep track of completed threads
    ManualResetEvent[] resetEvents = new ManualResetEvent[tasks.Length];

    // Launch each method in it's own thread
    for (int i = 0; i < tasks.Length; i++)
    {
        resetEvents[i] = new ManualResetEvent(false);
        ThreadPool.QueueUserWorkItem(new WaitCallback((object index) =>
            {
                int taskIndex = (int)index;

                // Execute the method
                tasks[taskIndex]();

                // Tell the calling thread that we're done
                resetEvents[taskIndex].Set();
            }), i);
    }

    // Wait for all threads to execute
    WaitHandle.WaitAll(resetEvents);
}

可以在这里找到有关此函数的更多详细信息:
http://newapputil.blogspot.in/2016/03/running-parallel-tasks-using.html


2
var task1 = SomeLongRunningTask();
var task2 = SomeOtherLongRunningTask();

await Task.WhenAll(task1, task2);

这种方法相较于Task.WaitAll的优点在于,它会释放线程并等待两个任务完成。

1
“Parallel” 还使用当前线程来执行操作,因此它不会阻塞等待操作完成的线程。如果您需要并行化同步的 CPU 绑定操作,则这是更好的选择。 - Eli Arbel
如果你只是想同时运行一些东西,但并不关心深层次的内容,那么这是最好、最简单和最现代化的方式。 - Timotei Oros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接