我想弄清楚我正在使用WebRequest/WebResponse轉換爲HttpClient的TPL程序中發生了死鎖。爲什麼Task.Run(()=> something)調用了一個等待死鎖的同步方法?
我有,創建100個任務,並把它們放入數組循環:
var putTasks = new Task[100];
for (var i = 0; i < 100; i++)
{
putTasks[i] = Task.Run(() => client.Put("something"));
}
Task.WaitAll(putTasks);
的代碼是掛在Task.WaitAll來看,在服務器端顯示的第一個請求完成,但其餘的都沒有。
關於這個問題的奇怪的部分(是的,它應該是異步通過,但它現在不正確,我試圖理解爲什麼它是完全異步之前它是死鎖)是客戶端。是看起來像這樣的同步方法:
string Put(string thing) { return PutAsync(string thing).GetAwaiter().GetResult(); }
和PutAsync樣子:
async Task<string> PutAsync(string thing)
{
//httpClient built up here
HttpContent content = new StringContent(thing);
var response = await httpClient.PutAsync("http://myuri", content);
var result = await response.Content.ReadAsStreamAsync();
// Do some stuff
}
它掛在裏面PutAsync是response = await httpClient.PutAsync
部分。我在UI線程中看到了大量關於死鎖的答案,但沒有一個修復(例如更改捕獲的上下文)有幫助。
理想情況下,我只是將所有異步完成,等待一切,但正如我所說的,我試圖弄清楚爲什麼僵局會發生,以及在發生什麼事情之前,我將所有事情分開 - 另一個問題這是一個其他人使用的庫,而且接口是同步方法,所以我不能只是將其更改爲異步並更新一堆隱藏的代碼。
PutAsync將創建它自己的任務。所以你聲明的任務數組是不需要的。刪除'Task.Run(()'把你的代碼放在一個方法中並標記爲'async'並等待'client.Put'調用 – William
我正在「掩飾」PutAsync'創建的任務 - 基本上,我是將一個同步庫轉換爲在後臺代碼中使用異步,所以'Put'方法不會返回一個'Task',它只是返回一個'string'。實際上,我可能在這裏完全錯誤 - 如果我讓它坐得夠久,它是否工作,所以我不知道它是否阻止共享HttpClient的連接池或其他東西 – HighlyUnavailable
@HighlyUnavailable如果它確實工作,那麼它不是一個死鎖。它可能是限制因爲有多少請求可以發送到 – i3arnon