如何使用async/await处理同步方法/任务

本文关键字:同步方法 任务 处理 await async 何使用 | 更新日期: 2023-09-27 18:27:33

我正在尝试了解如何将.net 4.5 async/await关键字与核心是同步的Task一起使用。即某种复杂的数学计算。我在下面的例子中使用了Thread.Sleep来模拟这个动作。我的问题是,有没有一种方法可以让这样的方法像异步方法一样运行?如果没有,你只需要做我在ThisWillRunAsyncTest方法中做的事情,并在该同步方法上做一些类似Task.Factory.StartNew的事情。有更干净的方法吗?

using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;
[TestFixture]
public class AsyncAwaitTest
{
    [Test]
    //This test will take 1 second to run because it runs asynchronously
    //Is there a better way to start up a synchronous task and have it run in parallel.
    public async void ThisWillRunAsyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(Task.Factory.StartNew(() => this.RunTask()));
        }
        await Task.WhenAll(tasks);
    }
    [Test]
    //This test will take 5 seconds to run because it runs synchronously.
    //If the Run Task had an await in it, this this would run synchronously.  
    public async void ThisWillRunSyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(this.RunTask());
        }
        await Task.WhenAll(tasks);
    }
    //This is just an example of some synchronous task that I want to run in parallel.
    //Is there something I can do in this method that makes the async keyword work?  I.e. this would run asynchronously when called from ThisWillRunSyncTest
    public async Task RunTask()
    {
        Thread.Sleep(1000);
    }
}

如何使用async/await处理同步方法/任务

一般来说,如果有并行工作要做,则应该使用Parallel或并行LINQ。

有时,将CPU绑定的工作视为异步工作(即在后台线程上运行)是很方便的。这就是Task.Run的作用(避免使用StartNew,正如我在博客上所描述的)。

同步方法应具有同步方法签名:

public void RunTask()
{
  Thread.Sleep(1000);
}

只有在调用代码需要的情况下(即,它是UI组件(如视图模型)的一部分),它们才应该封装在Task.Run中:

var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
  tasks.Add(Task.Run(() => this.RunTask()));
}
await Task.WhenAll(tasks);

这里的原则是Task.Run应该在调用中使用,而不是在实现中使用;我会在博客上详细介绍。

请注意,如果您有任何实际的复杂性,您应该使用Parallel或并行LINQ,而不是Task.Run任务的集合。Task.Run对小东西来说很好,但它没有并行类型所具有的所有智能。因此,如果这是库的一部分(不一定在UI线程上运行),那么我建议使用Parallel:

Parallel.For(0, 5, _ => this.RunTask());

最后,异步单元测试方法应该是async Task,而不是async void。NUnit v3已经删除了对async void单元测试方法的支持。