【问题标题】:Is this usage of await/async correct?这种等待/异步的用法正确吗?
【发布时间】:2016-09-25 07:01:19
【问题描述】:

我是 async/await 的新手,我想确保这种做法是正确的:

public async Task DoHeavyWorkAsync() 
{
    await Task.Run(() => {
        getResponseFromFarawaySlowServerAndDoSomethingWithIt();
    });
}

public async void ConsumeAsync()
{
    Task longRunningTask = DoHeavyWorkAsync();
    // do a lot of other stuffs here that does not depend on DoHeavyWorkAsync()
    await longRunningTask;
}

这种使用 async/await 的方式是正确的还是我做错了什么?

【问题讨论】:

  • 为什么在需要时才启动它?
  • 这段代码无法编译,您在ConsumeAsync 中缺少async 关键字
  • 这是桌面应用还是网络应用?
  • 这是一个桌面应用程序
  • 如果您能够使getResponseFromFarawaySlowServerAndDoSomethingWithIt 异步,请执行此操作,而不是用Task.Run 包装它。

标签: c# .net asynchronous async-await task-parallel-library


【解决方案1】:

你可以做几件事:

  1. DoHeavyWorkAsync中,你真的不需要使用await Task.Run生成状态机,你可以简单的return Task.Run

    public Task DoHeavyWorkAsync() 
    {
       return Task.Run(() => getResponseFromFarawaySlowServerAndDoSomethingWithIt());
    }
    
  2. async void 仅用于 异步事件处理程序。如果您的异步方法返回的是void,则它应该返回Task

    public async Task ConsumeAsync()
    
  3. 如果 DoHeavyWorkAsync 是基于 IO 的操作,则无需将其包装在 Task.Run 中,因为它本质上是异步的。只需使用await 即可。更重要的是,你不应该这样做async over sync。相反,如果需要,您应该让同步方法的调用者显式使用Task.Run

    public void DoHeavyWork()
    {
        getResponseFromFarawaySlowServerAndDoSomethingWithIt();  
    }
    

    然后将其显式包装在调用方法中:

    Task.Run(DoHeavyWork);
    

【讨论】:

    【解决方案2】:

    从 API 设计者的角度来看,我会考虑拆分方法 getResponseFromFarawaySlowServerAndDoSomethingWithIt 到:
    getResponseFromFarawaySlowServerdoSomething()
    然后你可以只用异步包装器包装长时间运行的方法

    然后使用:

    var response = await getResponseFromFarawaySlowServerAsync();
    doSomething(response);
    

    另一件有点味道的东西:getResponseFromFarawaySlowServer 本身不是异步的。如果可能,应该在该方法中等待 http 调用或 webservice 调用本身。目前您正在创建新线程,它什么都不做,只是等待。如果您改为等待 http 调用,这将是多余的

    所以

    string getResponseFromFarawaySlowServer(){
      string response = new WebClient().DownloadString(uri);
      ...
      return response
    }
    
    async Task<string> getResponseFromFarawaySlowServerAsync(){ Task.StartNew..
    

    你会直接:

    async Task<string> getResponseFromFarawaySlowServerAsync(){
      string response = await new WebClient().DownloadStringAsync(uri);
      ...
      return response;
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 1970-01-01
      • 2020-09-10
      • 1970-01-01
      • 1970-01-01
      • 2020-08-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      相关资源
      最近更新 更多