我很确定,这已经得到了解答,我阅读了许多相关的内容,但不知怎的,我没有让它在我的代码中工作。这是确切的代码库。
我的库中有这个异步方法,它在执行一些数据库条目时返回一个字符串:
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是否有任何好处?
我很确定,一些断开的链接将所有这些碎片连接在一起。有人可以向我解释一下吗?
答案 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。