等待/异步的这种用法是否正确

本文关键字:用法 是否 异步 等待 | 更新日期: 2023-09-27 18:29:21

我是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 的方式是正确的还是我做错了什么?

等待/异步的这种用法是否正确

您可以做几件事:

  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就可以了。更重要的是,您不应该通过同步进行异步。相反,您应该使同步方法的调用方显式使用 Task.Run ,如果需要的话:

    public void DoHeavyWork()
    {
        getResponseFromFarawaySlowServerAndDoSomethingWithIt();  
    }
    

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

    Task.Run(DoHeavyWork);
    

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

然后用法将:

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

另一件闻起来有点闻的东西:getResponseFromFarawaySlowServer本身不是异步的。 如果可能的话,应该在该方法中等待 HTTP 调用或 WebService 调用本身。目前您正在创建新线程 thad 什么都不做,只是等待。如果您等待 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;
}