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

本文关键字:方法 等待 异步 Lambda 包括 | 更新日期: 2023-09-27 18:28:59

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

A

假设您已经在库中创建了一个类似以下的方法,以便从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上下文分割成几个小的调用块,对吧?或者我不知道从你声明一个方法async的那一刻起,它是否会为里面的所有操作创建一个Task?

如果是的话,那就太好了,没问题,我们可以宣布它是异步的,然后继续我们的生活。

让我们说不,我想采取以下方法,这样我就不会干扰GUI,直到我的整个方法调用完成并得到结果,所以在我的调用方法中做点什么。

B

另一种方法是

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

它只是让我有点bug,我真的很想了解异步编程的细节。

那么,A范式是正确的方法吗?只有当代码中的Task lambda完全同步时,才使用B范式?提前谢谢。

谨致问候。

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

编写async方法的正确方法是在不需要在捕获的上下文上继续时使用ConfigureAwait(continueOnCapturedContext: false)。这通常针对所有"库"代码。

这将把我的GUI上下文分割成几个小的调用块,对吧?

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

或者我不知道从你声明一个方法async的那一刻起,它是否会为里面的所有操作创建一个Task?

是的,async将创建一个代表async方法的Task。然而,存在Task并不意味着它的代码在后台线程上运行。

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

我想知道在异步任务中使用Task.Factory.StartNew的想法是从哪里来的。如果您想在后台线程上运行代码,Task.Run会更出色。


我的博客上有一个async的介绍,你可能会觉得有帮助。