如何以及何时从等待(异步)方法获取返回

时间:2017-02-05 17:42:16

标签: c# .net async-await

我很确定,这已经得到了解答,我阅读了许多相关的内容,但不知怎的,我没有让它在我的代码中工作。这是确切的代码库。

我的库中有这个异步方法,它在执行一些数据库条目时返回一个字符串:

public class MyLibrary
{
public async Task<string> DoSomethingAsync()
{
    return await DoAsync();
} 

// some private method, with multiple parameters
private Task<string> DoAsync()
{
    return Task.Run(() => Do());
}
}

现在在UI上,下面导致了冻结状态或死锁:

var myTask = MyLibraryobject.DoSomethingAsync();
console.Write(myTask.Result); 

由于我的电话是可以接受的,我认为,UI线程等待我的电话完成其业务并填充结果,不是吗?或者由于调用是在另一个线程上运行的,当我的光标到达第2行时,任务可能还没有完成。那么现在呢?光标将等待任务完成或任务完成后第2行执行?听起来和我同步..

另外,如果有的话,我想明确地&#39;等到任务完成,我该如何执行?一些帖子,建议如下所示,这给了我结果,但又造成了一些混乱:

var myTask = Task.Run(async () => await MyLibraryobject.DoSomethingAsync());
myTask.Wait();
console.Write(myTask.Result);

上面发生了什么?我为什么要创建另一个任务并将其设置为等待?我不能等待异步方法使用的线程吗?再一次,我显然在这里遗漏了一些基本的东西。

最后,这是一个异步调用,但UI线程正在等待它完成,因此给我的印象是它是同步的。我认为对吗?那么异步方法的主要目的是什么,它返回一些东西,UI等待它完成?

另外,非同步和异步的即发即弃电话之间的区别是什么?对于这样的调用,返回Task而不是void是否有任何好处?

我很确定,一些断开的链接将所有这些碎片连接在一起。有人可以向我解释一下吗?

2 个答案:

答案 0 :(得分:2)

您应该从我的async intro开始,然后在async best practices上跟进我的文章。他们几乎回答了你所有的问题。

详情......

  

如何以及何时从等待(异步)方法获取返回

您应该使用await从异步任务中获取结果。

  

我的库中有这个异步方法,它在执行一些数据库条目时返回一个字符串

然后它不应该使用Task.Run。它应该使用自然异步API,例如,实体框架FirstAsync

  

由于我的电话是可以接受的,我认为,UI线程等待我的电话完成其业务并填充结果,不是吗?

没有。由于您的代码正在调用Result,因此用户界面正在阻止。 Result是阻止通话。

  

听起来和我同步..

这是因为您使用Result使其同步。如果您使用await,则代码将串行执行,但异步执行

  

另外,如果有的话,我想明确地&#39;等到任务完成,我该如何执行?

您的代码已经在执行此操作。在任务完成之前,它会明确阻止。如果将其更改为正确使用await,则在任务完成之前,它将显式等待(但不会阻塞)。

  

一些帖子,建议如下所示

没有。不必要地使用Task.Run

  

我不能等待异步方法使用的线程吗?

纯异步方法没有他们使用的线程。

  

然后异步方法的主要目的是什么,它返回一些东西,UI等待它完成?

Async在与await一起消费时有意义。

答案 1 :(得分:1)

  

现在在UI上,下面导致了冻结状态或死锁:

var myTask = MyLibraryobject.DoSomethingAsync();

这阻止了UI,因为它没有被等待。您只需要等待异步方法

string res = await MyLibraryobject.DoSomethingAsync();

以上内容也应该放在异步上下文的UI中。

编辑 - 回复评论do&#34;你的意思是另一个包装异步方法,它返回Task<string> ...&#34;?不,我不是。当我在异步上下文中编写&#34;&#34;我的意思是将async关键字添加到订阅事件中,比如按钮单击,如果您在代码后面或代理命令实现中,如果您处于GUI的更高级的MVVM实现中。

此外,你的类库应该做一些真正异步的事情,而不仅仅是启动一个任务并将其包装在一个正式的异步方法中,就像你的DoAsync一样。

编辑 - 回复评论&#34;应该如何避免&#34;它?如果你不能一直做异步,只需保持库和API同步并通过启动一个单独的线程来调用同步api来取消阻止UI。