async并等待不按预期返回调用者

时间:2013-10-07 19:04:53

标签: c# async-await

我有一个简单的asyncawait示例,我正在努力完成并且执行没有按照我的预期返回到调用者。这是顶级方法:

protected async void MyDDL_SelectedIndexChanged(object sender, EventArgs e)
{
  Task longRunningTask = LongRunningOperationAsync();
  DoOtherStuff1();
  DoOtherStuff2();
  DoOtherStuff3();
  await longRunningTask;
}

以下是LongRunningOperationAsync方法无法按预期工作并同步运行:

 private async Task LongRunningOperationAsync()
 {
   var myValues = await GetStuffViaLongRunningTask();
   //Code to work with myValues here...
 }

以下是GetStuffViaLongRunningTask

的定义
private async Task<IList<MyClass>> GetStuffViaLongRunningTask()
{

    //...Calls to get and build up IList<MyClass>
    return results;

}

问题是上面的代码返回调用方并开始运行DoOtherStuff1();方法,正如我所料。但是,不是调用我自己的方法并将其替换为await Task.Delay(10000);调用,就像所有简单示例所示, 代码按预期工作:

 private async Task LongRunningOperationAsync()
 {
   //Returns to caller as expected:
   await Task.Delay(10000);
 }

使用上述代码的来电者longRunningTask的状态为WaitingForActivation,而不是RanToCompletion,表明它仍在处理中。

您可能会说我的GetStuffViaLongRunningTask()方法运行得太快,我看不到结果。但是,它总是需要3-7秒才能运行,您可以在调试时判断调用是否阻塞并且同步

我在这里做错了什么,所以当我到达LongRunningOperationAsync()字以便在该方法中调用await时,我对LongRunningOperationAsync的调用是不是异步工作?

2 个答案:

答案 0 :(得分:4)

假设//...Calls to get and build up IList<MyClass>是同步CPU绑定工作,问题是GetStuffViaLongRunningTask在它结束或点击其第一个await调用之前不会返回。您应该在该方法上收到编译器警告,因为它是async方法,其中没有await

相反,该方法不应该是async,以清楚地向其调用者表明它是同步工作。只需将签名调整为:

private IList<MyClass> GetStuffViaLongRunningTask()

然后在调用它时使用Task.Run来确保在另一个线程中完成长时间运行的CPU绑定工作:

private async Task LongRunningOperationAsync()
{
    var myValues = await Task.Run(() => GetStuffViaLongRunningTask());
    //Code to work with myValues here...
}

答案 1 :(得分:1)

  

//...Calls to get and build up IList<MyClass>

您需要告诉我们正在进行哪些通话。如果要对此结构使用async / await,则需要进行异步调用。

如果您的GetStuffViaLongRunningTask功能没有执行异步调用,那么您可以开始执行以下新任务:

private Task<IList<MyClass>> GetStuffViaLongRunningTask()
{
    return Task.Factory.StartNew(() =>
    {
        //...Calls to get and build up IList<MyClass>
        // You can make synchronous calls here
        return list;
    });
}