在.Net 4.5中使用async/await编写多线程方法

Mil*_*cho 7 .net c# asynchronous

我有一个小问题.

我承认在.Net 4.5之前我没有多次使用多线程,但是有了新的async/await功能,我决定尝试一下.我开始尝试它,一切似乎都很好,但我无法在网络上的任何地方找到解决我的"问题"的方法.

所以每个人都解释了如何await使用.Net平台的新转换方法(例如WriteAsync(),ReadAsync()等等),但是如果我想将它用于我自己的方法呢?例如,假设我正在执行一项极其昂贵的计算,并且希望我的所有4个内核都在使用它.我会有类似的东西:

async Task DoLotsOfWork<T>(T[] data, int start, int end)
{
    //Do very expensive work
}
Run Code Online (Sandbox Code Playgroud)

但由于我没有await关键字,因此该方法仅被视为同步方法.我想从外面调用它4次,以便它可以在我的所有核心上运行,同时我向用户显示一些合理的东西(例如"请等待......").我能够弄清楚的唯一解决方案是await Task.Yield();在方法的开头添加一个.像这样的东西:

async Task DoLotsOfWork<T>(T[] data, int start, int end)
{
    await Task.Yield();
    //Do very expensive work
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,该方法将按照我的预期行事.但是有更好的解决方案吗?我觉得应该比编写那行代码更容易/更明智.我知道我可以创建一个Task/Thread对象并调用该Start()方法,但这需要更多的工作.我只是认为使用新的异步/等待功能这种事情会更容易.

Ser*_*rvy 15

因此,首先,您需要一种同步执行非常昂贵的工作的方法:

public void DoLotsOfWork<T>(T[] data, int start, int end) 
{
    Thread.Sleep(5000);//placeholder for real work
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以用来Task.Run在线程池线程中启动这项工作的多个实例.

List<Task> tasks = new List<Task>();
for(int i = 0; i < 4; i++)
{
    tasks.Add(Task.Run(()=>DoLotsOfWork(data, start, end));
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以进行非阻塞等待,直到完成所有这些:

await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)

  • @StephenCleary问题是并行方法阻塞直到结果完成,所以你最终需要将`Parallel.For`或`Foreach`抛入`Task.Run`,如果你当前在,例如, UI上下文并且在任务完成之前无法阻止. (3认同)
  • @Servy:是的。但是`Parallel`的好处是它将自动分区工作,以充分利用可用的内核。如您所说,您可以将其包装在Task.Run中,以获得代表并行工作的Task。 (2认同)