我调用异步方法和一些死锁。现在我完全不知道为什么会发生这种事。我不认为这是一个标准的死锁,因为我在Main方法中调用Task.Result,而不是在UI线程中。此外,我还尝试在不调用Task的情况下使用async Main。但结果是一样的。
问题出在WinForms项目上。一切都从Main方法开始:
bool res = Task.Run(() => contr.RegisterPremiseAllInOne()).Result;这是在新任务中对异步方法RegisterPremiseAllInOne的简单调用。
接下来会发生什么..。RegisterPremiseAllInOne的工作原理更像这样(简化模型):
public async Task<bool> RegisterPremiseAllInOne()
{
AppUser loggedAppUser = await appUserContr.GetLoggedAppUser(); // <-- everything works fine here
if(loggedAppUser == null)
return false;
var premises = await GetPremisesForLoggedUser(); //at the end there is a deadlock
}现在我将向您展示每个方法的调用是做什么的(所有内容都以对WebApi的rest查询结束):
GetLoggedAppUser ->
await API.Users.GetLoggedAppUser() ->
await ClientHelper.GetObjectFromRequest<Appuser>("AppUsers/logged") ->
await SendAsyncRequest() ->
await HttpClient.SendAsync()我希望这篇文章的可读性很好。
这条路运行得很好。有趣的是,GetPremisesForLoggedUser与GetLoggedAppUser部分收敛,看起来像这样:
GetPremisesForLoggedUser ->
await API.Premises.GetForLoggedUser() ->
await ClientHelper.GetListFromRequest<premise>("premises/logged") ->
await SendAsyncRequest() ->
await HttpClient.SendAsync()如你所见,这里有一条笔直的小路。调用API并最终发送http请求。
来自HttpClient的SendAsync中存在死锁。我不知道为什么。然而,第一条路径运行得很好。
在服务器端,一切都很好。服务端返回成功响应。但是客户端挂了。
我觉得应该能行得通。我不会把synchronious和async代码混在一起。所有方法都返回Task<T>并标记为async。
也许有人知道问题出在哪里?也许你想看看调试窗口中的一些截图:并行堆栈/任务?
发布于 2018-05-24 20:24:49
好了,多亏了@usr和@Evk,我找到了bug。然而,这是标准的UI死锁,但更多的是伪装。
在我调用GetPremisesForLoggedUser()之前,我使用工厂(IoC容器)创建了一个表单:
IPremisePickerView view = objFactory.Resolve<IPremisePickerView>();
var premises = await GetPremisesForLoggedUser();创建窗体时,该窗体所属的线程会自动成为UI线程。我认为这是在Form类中完成的。
所以我调用的是await GetPremisesForLoggedUser()
在UI线程上。所以很可能所有的任务都是在UI线程上开始运行的(从某个点开始)。但是这是否意味着在Main中调用的Task.Run.Result阻塞了等待结果的UI线程?我不确定,因为这是在主线程(在本例中不是UI线程)上调用的。因此,如果有人能编造我的答案,那就太好了。
无论如何,在将表单创建移至async方法调用下面之后,一切都开始工作了。
https://stackoverflow.com/questions/50506428
复制相似问题