这个await/async的用法是否正确?

4

我刚接触 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的方式正确吗,或者我做错了什么?

3
这段代码无法编译,你在 ConsumeAsync 函数中缺少了 async 关键字。 - Yuval Itzchakov
这是一个桌面应用程序。 - Chin
不,这是不正确的。 - Hamid Pourjam
1
如果您能够将 getResponseFromFarawaySlowServerAndDoSomethingWithIt 设为异步,那么请这样做,而不是用 Task.Run 包装它。 - dcastro
@DanielA.White - 开始长时间操作是有意义的,这样它可能会在您完成其他缓慢的事情之前完成。我怀疑这实际上是问题的主要部分 - 是否可以提前开始操作并在以后“等待”(如果是问题-是的)。 - Alexei Levenkov
显示剩余6条评论
2个回答

7

你可以做以下几件事情:

  1. In DoHeavyWorkAsync, you don't really need to generate a state machine using await Task.Run, you can simply return Task.Run:

    public Task DoHeavyWorkAsync() 
    {
       return Task.Run(() => getResponseFromFarawaySlowServerAndDoSomethingWithIt());
    }
    
  2. async void is ment solely for async Event Handlers. If your async method is void returning, it should return a Task instead:

    public async Task ConsumeAsync()
    
  3. If DoHeavyWorkAsync is an IO based operation, there is no need to wrap it inside a Task.Run as it is inherently asynchronous. Simply using await will do. More-so, you shouldn't do async over sync. Instead, you should make the caller of the synchronous method explicitly use Task.Run, if needed at all:

    public void DoHeavyWork()
    {
        getResponseFromFarawaySlowServerAndDoSomethingWithIt();  
    }
    

    and then explicitly wrap it in the calling method:

    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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接