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

时间:2014-10-23 17:53:40

标签: c# async-await

我正在尝试了解如何使用.net 4.5 async / await关键字和一个任务,它的核心是同步的。即某种复杂的数学计算。我使用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);
    }
}

1 个答案:

答案 0 :(得分:12)

作为一般规则,如果您要执行 parallel 工作,则应使用Parallel或并行LINQ。

有时候将CPU绑定工作视为异步(即在后台线程上运行)很方便。这是Task.Run的用途(避免使用StartNew,因为我describe on my blog)。

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

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

如果调用代码需要它们,它们应该只包含在Task.Run中(即,它是UI组件的一部分,例如视图模型):

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

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

请注意,如果您有任何真正的复杂性,则应使用Parallel或并行LINQ而不是Task.Run任务的集合。 Task.Run适用于小东西,但并不具备并行类型所具有的所有智能。所以,如果这是库的一部分(并且不一定在UI线程上运行),那么我建议使用Parallel

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

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