Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在异步方法上调用.Wait()和Task.Run().Wait()之间的区别_C#_Asp.net_Asynchronous_Async Await - Fatal编程技术网

C# 在异步方法上调用.Wait()和Task.Run().Wait()之间的区别

C# 在异步方法上调用.Wait()和Task.Run().Wait()之间的区别,c#,asp.net,asynchronous,async-await,C#,Asp.net,Asynchronous,Async Await,我在ASP.NET WebForms网站上有一个服务器端单击事件。在本例中,我调用一个方法,该方法反过来调用其异步伙伴方法,在调用中添加.Wait() 然后,该方法向下几个级别(即调用另一个异步方法,该方法调用另一个异步方法,等等),并最终在HttpClient对象上调用一个异步方法。在这一点上,线似乎消失在兔子洞里;该方法从不回调 现在,我知道异步调用系列可以按预期工作,因为同样的代码也可以从Web API控制器调用(控制器方法调用第一个方法的异步版本,而不是同步的“partner”方法),该

我在ASP.NET WebForms网站上有一个服务器端单击事件。在本例中,我调用一个方法,该方法反过来调用其异步伙伴方法,在调用中添加
.Wait()

然后,该方法向下几个级别(即调用另一个异步方法,该方法调用另一个异步方法,等等),并最终在HttpClient对象上调用一个异步方法。在这一点上,线似乎消失在兔子洞里;该方法从不回调

现在,我知道异步调用系列可以按预期工作,因为同样的代码也可以从Web API控制器调用(控制器方法调用第一个方法的异步版本,而不是同步的“partner”方法),该方法是完全异步的,并且它会按预期返回

所以基本上我有这样的东西,永远不会回来

protected void btn_Click(object sender, EventArgs e)
    > Class1.DoSomething()
        > Class1.DoSomethingAsync.Wait()
            ...
                > await ClassN.Authenticate()
                  {
                    await myHttpClient.PostAsync()  // never returns
                  }
我确实尝试在第一个异步方法上使用
.ConfigureAwait(false)
,但没有成功

我也有这个,它会返回

但我不知道为什么

有人能解释一下打电话和打电话的区别吗

Class1.DoSomethingAsync.Wait()
和呼唤

Task.Run(async () => await Class1.DoSomethingAsync()).Wait()

我在我的博客文章和MSDN上的文章中解释了这种行为

线似乎从兔子洞里消失了;该方法从不回调

发生这种情况的原因是,
wait
s试图在ASP.NET上下文上恢复,但请求线程(使用该ASP.NET上下文)在等待任务完成时被阻止。这就是导致死锁的原因

我确实尝试在第一个异步方法上使用.ConfigureAwait(false),但没有成功

为了使用
ConfigureAwait(false)
避免此死锁,必须将其应用于调用的每个方法中的每个
await
。因此
DoSomethingAsync
必须对每个
wait
使用它,每个
DoSomethingAsync
调用的方法都必须对每个
wait
使用它(例如,
Authenticate
),这些方法调用的每个方法都必须对每个
wait
使用它(例如,
PostAsync
),等等。请注意,在这里的末尾,您依赖于库代码,事实上,
HttpClient
在过去错过了其中一些

我发现,如果我将第一个版本更改为[使用
Task.Run
],则可以使其正常工作

是的
Task.Run
将在没有任何上下文的线程池线程上执行其委托。这就是为什么没有死锁的原因:没有一个
wait
s尝试在ASP.NET上下文中恢复


你为什么不用正确的方法呢。异步无效btn_单击并等待Class1.DoSomethingAsync()

不要使用任务。使用已经异步的方法运行,这是对线程的浪费。只需更改按钮的签名即可单击eventhandler

正确的答案是:不要阻塞异步代码。只需使用
async void
事件处理程序,并使用
wait
即可


p.S.ASP.NET核心不再具有ASP.NET上下文,因此您可以根据需要进行阻止,而无需担心死锁。当然,你还是不应该这样做,因为这样做效率很低。

为什么不正确使用它呢
async void btn_单击
并等待Class1.DoSomethingAsync()?不要使用
任务。使用已经异步的方法运行
,这是对线程的浪费。只需将
按钮的签名更改为@user3185569suggested@user3185569-我没有使用它,因为我不知道我可以在服务器端WebForms事件上使用
async
。谢谢你向我指出这一点。我对正确答案有部分不同意见。。。有时您需要从普通的旧异步代码调用异步方法,这种代码使用线程、锁和信号量,或者在一个很长的堆栈中,您不想让
async Task
病毒一直侵扰到根。@LouisSomers:可以从同步代码调用异步代码,但没有一种解决方案可以在所有情况下都有效。我认为你评论的关键是“不要”——几乎总是可以用正确的方式来做;只是人们不想(或者,更常见的情况是,企业不会优先考虑工作)。
Class1.DoSomethingAsync.Wait()
Task.Run(async () => await Class1.DoSomethingAsync()).Wait()