在包括Lambda的异步/等待方法上的正确方法

时间:2013-08-24 23:28:46

标签: c# task-parallel-library async-await

我想展示两种关于异步编程的范例并听取你的意见。

:一种。

假设您已在库中创建了类似以下的方法,以便从GUI客户端使用它。

public async Task<TestObject> DoSomeWork(string aParam1, object aParam2)
{
   TestObject testObj = new TestObject();
   ...fill in params to testObj...
   await MethodCallAsync(testObj);
   ....do other work synchronous.....
   ....continue fill testObj properties...
   await Task.Delay(1000) // just a delay for no reason
   ...continue synchronous work.....
   return testObj;
}

好的,但这会将我的GUI上下文切换成小的调用件,对吗?或者我不知道从声明方法异步的那一刻起,它是否会为内部的所有操作创建一个任务?

如果是,那么很好,没问题,我们可以宣布它是异步的并继续我们的生活。

让我们说不,我想采取以下方法,所以我不会打扰GUI,直到我的整个方法调用完成并取结果,所以在我的调用方法中做一些事情。

另一种方法是。

public async Task<TestObject> DoSomeWork(string aParam1, object aParam2)
{
   TestObject testObj = new TestObject()
   ..fill state params....
   return await Task.Factory.StartNew((state) =>
   {
      //But now I need to do async/await in here
      // is it a good practice to async await lambdas?
      // async/await practices say it's ok as long sas it is not becoming async void
      // which in our case is not.
      await MethodCallAsync(testObj);
       ....do other work synchronous.....
       ....continue fill state properties...
       await Task.Delay(1000) // just a delay for no reason
       ...continue synchronous work.....
       return state; // Our state and TestObject to examine after completion

   }, testObj);
}

我们现在的问题不仅仅是我们应该将lambda异步化,比如你这样做,它会返回Task<Task<TestObject>>并且我们绝对不想要它。

你应该在管道中调用它,很可能是你的GUI类。

private async void SomethingClickedOrTouched(object sender, EventArgs e)
{
   await RunThisAsyncToDoYourJob();
}

private async Task RunThisAsyncToDoYourJob()
{
   TestObject testObj = await myObject.DoSomeWork("param1", anotherObject);
}

它只是让我感到烦恼,我真的想要了解异步编程的细节。

那么,A范式无论如何都是正确的方法,只有当代码中的任务lambda完全同步时才使用B范例? 提前谢谢。

问候。

1 个答案:

答案 0 :(得分:6)

编写async方法的正确方法是在需要在捕获的上下文上恢复时使用ConfigureAwait(continueOnCapturedContext: false)。这通常是针对所有“库”代码完成的。

  

这会将我的GUI上下文切换成小的调用片段,对吗?

是(因为您没有使用ConfigureAwait)。

  

或者我不知道从声明方法异步的那一刻开始,它是否会为内部的所有操作创建一个Task?

是的,async将创建代表Task方法的async。但是,存在Task这一事实并不意味着其代码在后台线程上运行。

  

它将返回Task<Task<TestObject>>,我们绝对不希望这样。

我想知道每个人都想到使用Task.Factory.StartNew进行异步任务的想法。 Task.Run is superior if you want to run code on a background thread


我有async intro on my blog你可能会觉得有帮助。