[英]Why does this wrapping in Task.Run remove deadlock from asp.net core?
[英]In the context of ASP.NET, why doesn't Task.Run(…).Result deadlock when calling an async method?
我用一個控制器和一個方法創建了一個簡單的WebApi項目:
public static class DoIt
{
public static async Task<string> GetStrAsync(Uri uri)
{
using (var client = new HttpClient())
{
var str = await client.GetStringAsync(uri);
return str;
}
}
}
public class TaskRunResultController : ApiController
{
public string Get()
{
var task = Task.Run(() =>
DoIt.GetStrAsync(new Uri("http://google.com"))
);
var result = task.Result;
return result;
}
}
我非常了解async / await和tasks; 斯蒂芬克萊里幾乎虔誠地跟隨他。 只是存在.Result
讓我焦慮,我希望這會陷入僵局。 我知道Task.Run(...)
是浪費的,導致在等待異步DoIt()
完成時占用一個線程。
問題是這不是死鎖 ,而是讓我心悸。
我看到一些答案,如https://stackoverflow.com/a/32607091/1801382 ,我還發現當lambda正在執行時, SynchronizationContext.Current
為null。 但是,我也有類似的問題,問為什么上面的代碼會出現死鎖,而且我看到在使用了ConfigureAwait(false)
(不捕獲上下文)和.Result
情況下發生了死鎖。
是什么賦予了?
Result
本身不會導致死鎖。 死鎖是指代碼的兩個部分都在等待彼此。 Result
只是一次等待,因此它可能是死鎖的一部分,但它不一定總是導致死鎖。
在標准示例中 , Result
在保持上下文的同時等待任務完成,但是任務無法完成,因為它正在等待上下文空閑 。 所以有一個僵局 - 他們正在等待對方。
ASP.NET Core根本沒有上下文 ,因此Result
不會死鎖。 (由於其他原因,它仍然不是一個好主意,但它不會陷入僵局 )。
問題是這不是死鎖,而是讓我心悸。
這是因為Task.Run
任務不需要完成上下文。 所以調用Task.Run(...).Result
是安全的。 Result
正在等待任務完成,並且它保持上下文(阻止請求的任何其他部分在該上下文中執行),但這沒關系,因為Task.Run
任務根本不需要上下文。
在ASP.NET上, Task.Run
仍然不是一個好主意(出於其他原因),但這是一種非常有用的技術,不時有用。 它不會死鎖,因為Task.Run
任務不需要上下文。
但是,我也有類似的問題,問為什么上面的代碼會出現死鎖,
相似但不完全相同。 仔細查看這些問題中的每個代碼語句,並問自己它運行的上下文。
我已經看到在與.Result一起使用ConfigureAwait(false)(不捕獲上下文)的情況下會發生死鎖。
Result
/上下文死鎖是一個非常常見的 - 可能是最常見的死鎖。 但它不是那里唯一的僵局。
這是一個更加困難的死鎖示例 ,如果您在 async
代碼中阻塞( 沒有上下文),則會出現這種死鎖。 但是,這種情況更為罕見。
我會以相反的方式給你一個簡短的答案:如何產生死鎖:
讓我們從一個執行同步的Click
處理程序開始,並將一些異步調用卸載到一個單獨的Task,然后等待結果
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var t = Task.Run(() => DeadlockProducer(sender as MenuItem));
var result = t.Result;
}
private async Task<int> DeadlockProducer(MenuItem sender)
{
await Task.Delay(1);
Dispatcher.Invoke(() => sender.Header = "Life sucks");
return 0;
}
異步方法正在做另一件壞事:它試圖同步帶來一些UI更改,但UI線程仍在等待任務結果...
所以基本上, Task.Run
已經完成了一半,並且可以用於很多格式良好的異步代碼,但是有很多方法可以解決它,所以它不是一個可靠的解決方案。
這個示例代碼是在WPF的上下文中編寫的,但我想ASP.Net可能會被濫用來產生類似的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.