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

Posted

技术标签:

【中文标题】如何使用 async/await 处理同步方法/任务【英文标题】:How to deal with synchronous method/task using async/await 【发布时间】:2014-12-19 11:41:17 【问题描述】:

我正在尝试了解如何将 .net 4.5 async/await 关键字与核心是同步的任务一起使用。 IE。某种复杂的数学计算。在下面的示例中,我使用了 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);
    

【问题讨论】:

如果RunTask 是同步的,那么它根本不应该返回Task,而将其提升到任务中应该由调用者完成。 您可能想阅读此博客:blogs.msdn.com/b/ericlippert/archive/2010/10/29/… 【参考方案1】:

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

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

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

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应该用在调用中,而不是实现中;我会详细介绍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 单元测试方法的支持。

【讨论】:

这很有帮助。感谢您的信息。

以上是关于如何使用 async/await 处理同步方法/任务的主要内容,如果未能解决你的问题,请参考以下文章

Angular请求同步async、await、toPromise使用方式

async await 同步方法调用异步方法死锁

async/await 的使用

async/await 来处理异步/同步

vue中使用async/await的实践

JS不使用async/await解决数据异步/同步问题