[英]Task.WaitAll() deadlocking
我想在 xUnit 測試中多次調用異步方法,並在繼續執行之前等待所有調用完成。 我讀到我可以將Task.WhenAll()
和Task.WaitAll()
用於這種情況。 然而,由於某種原因,代碼是死鎖的。
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList();
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = _attributesServiceClient.CreateLdapEntry(led);
task.Start();
creationTasks.Add(task);
}
Task.WaitAll(creationTasks.ToArray()); //<-- deadlock(?) here
//await Task.WhenAll(creationTasks);
var result = await _ldapAccess.GetLdapEntries();
result.Should().BeEquivalentTo(ldapEntries);
}
public async Task<LdapEntryDto> CreateLdapEntry(LdapEntryDto ldapEntryDto)
{
using (var creationResponse = await _httpClient.PostAsJsonAsync<LdapEntryDto>("", ldapEntryDto))
{
if (creationResponse.StatusCode == HttpStatusCode.Created)
{
return await creationResponse.Content.ReadAsAsync<LdapEntryDto>();
}
throw await buildException(creationResponse);
}
}
被測系統是HttpClient
的包裝器,它調用 Web 服務, await
響應,並且可能await
讀取最終反序列化並返回的響應內容。
當我將測試中的foreach
部分更改為以下內容時(即,不使用Task.WhenAll() / WaitAll()
),代碼運行時不會出現死鎖:
foreach (var led in ldapEntries)
{
await _attributesServiceClient.CreateLdapEntry(led);
}
究竟發生了什么?
編輯:雖然這個問題已被標記為重復,但我看不出鏈接的問題與這個問題有什么關系。 鏈接中的代碼示例都使用.Result
,據我所知,它會阻止執行,直到任務完成。 相反, Task.WhenAll()
返回一個可以等待並在所有任務完成后完成的任務。 那么為什么等待Task.WhenAll()
死鎖呢?
您發布的代碼不可能具有所描述的行為。 第一次調用Task.Start
會拋出InvalidOperationException
,測試失敗。
我讀到我可以將 Task.WhenAll() 和 Task.WaitAll() 用於這種情況。
不; 要異步等待多個任務,您必須使用Task.WhenAll
,而不是Task.WaitAll
。
例子:
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = new List<int> { 0, 1 };
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = CreateLdapEntry(led);
creationTasks.Add(task);
}
await Task.WhenAll(creationTasks);
}
public async Task<string> CreateLdapEntry(int ldapEntryDto)
{
await Task.Delay(500);
return "";
}
Task.WaitAll()
會死鎖,因為它在任務未完成時阻塞了當前線程(並且由於您使用的是async/await
而不是線程,您的所有任務都在同一線程上運行,並且您不會讓您的等待的任務返回調用點,因為它們正在運行的線程 -與您調用Task.WaitAll()
的線程相同- 被阻塞)。
不知道為什么WhenAll
在這里也讓你陷入僵局,但絕對不應該。
PS:您不需要對async
方法返回的任務調用Start
:它們在創建時已經“熱”(已經啟動)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.