我創建了一個簡單的WebAPI項目,一個控制器和一個方法:在ASP.NET的上下文中,爲什麼在調用異步方法時沒有Task.Run(...)。結果死鎖?
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;
}
}
我有異步有很好的理解/等待和任務;幾乎虔誠地跟隨斯蒂芬克利裏。只是.Result
的存在讓我着急,我預計這會陷入僵局。據我所知,Task.Run(...)
是浪費,導致線程被佔用,等待異步DoIt()
完成。
問題是這不是死鎖,它給我心悸。
我看到一些答案,如https://stackoverflow.com/a/32607091/1801382,我也觀察到SynchronizationContext.Current
在執行lambda時爲空。但是,也有類似的問題要問我爲什麼上面的代碼確實是死鎖,並且我發現在使用ConfigureAwait(false)
(不捕獲上下文)和.Result
的情況下會發生死鎖。
什麼給?
謝謝,斯蒂芬。我懷疑答案基本上是「這是因爲Task.Run任務不需要上下文來完成」,但是猶豫稱這個「安全」。我瞭解其他影響。感謝封鎖的例子;因爲現在是2017年,更罕見的情況仍然有效嗎?您還聲明這不會發生在GUI或ASP.NET代碼中 - 在哪種情況下_does_它會死鎖? – aholmes
是的。 'await'仍然使用'ExecuteSynchronously',所以更稀有的場景仍然有效。在這種情況下,這是一個死鎖,兩個線程池線程正在等待對方。 –