C# Task.WaitAll()死锁
我想在xUnit测试中多次调用异步方法,并等待所有调用完成后再继续执行。我读到我可以使用C# Task.WaitAll()死锁,c#,async-await,task,C#,Async Await,Task,我想在xUnit测试中多次调用异步方法,并等待所有调用完成后再继续执行。我读到我可以使用Task.WhenAll()和Task.WaitAll()来准确地描述这个场景。然而,由于某种原因,代码处于死锁状态 [Fact] public async Task GetLdapEntries_ReturnsLdapEntries() { var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList(); var c
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);
}
}
到底发生了什么
编辑:虽然这个问题被标记为重复问题,但我看不出链接的问题与这个问题有什么关系。链接中的代码示例都使用.Result
,据我所知,它会阻止执行,直到任务完成。相反,Task.WhenAll()
返回一个可以等待的任务,该任务在所有任务完成后完成。那么,为什么正在等待Task.WhenAll()
死锁?Task.WaitAll()
将死锁,原因很简单,因为它会在任务未完成时阻塞当前线程(由于您使用的是async/await
而不是线程,因此您的所有任务都在同一个线程上运行,并且您不会让等待的任务返回到调用点,因为它们正在运行的线程(即调用Task.WaitAll()
-)被阻塞的线程)
虽然不确定为什么在这里所有的也会死锁,但它绝对不应该
PS:对于由async
方法返回的任务,您不需要调用Start
:它们在创建时就已经“热”(已启动)您发布的代码不可能描述其行为。第一次调用Task.Start
将抛出InvalidoOperationException
,测试失败
我读到我可以使用Task.WhenAll()和Task.WaitAll()来实现这个场景
否;若要异步等待多个任务,必须使用Task.whalll
,而不是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 "";
}
[事实]
公共异步任务GetLdapEntries\u ReturnsLdapEntries()
{
var ldapEntries=新列表{0,1};
var creationTasks=新列表();
foreach(ldapEntries中的var led)
{
var任务=CreateLdapEntry(led);
creationTasks.Add(任务);
}
等待任务。WhenAll(创建任务);
}
公共异步任务CreateLdapEntry(int-LDapentryTo)
{
等待任务。延迟(500);
返回“”;
}
@Servy感谢您的链接,但我看不到与任务的关系
?副本准确地解释了死锁发生的原因以及如何处理。只需通读答案。这就是我在评论之前所做的,我仍然看不到与WaitAll
或whalll
的关系,后者创建了一个等待的任务,并且仍然死锁;我不使用。Result
a纽约,告诉我“再读一遍”很遗憾,这对我没有帮助。你在使用Task.WaitAll时收到编译器警告吗?我怀疑你收到了,因为你的方法被标记为异步。它没有调用wait。它也没有返回任务,所以看起来它甚至不会编译。总之,Task.WaitAll绝对不应该被使用。这是什么类型的应用程序(ASP.NET、ASP.NET Core、WPF、Win Forms等)?@mason哪一个?所有方法都返回Task
或Task
Task.WaitAll()
不能等待。我没有收到任何编译器警告或错误,此代码工作正常(除了死锁,使用备用foreach
版本按预期工作)。感谢您的输入,但它不会引发任何异常,我已经多次运行测试,总是遇到死锁。明天我将用您的示例进行尝试。正如我在原始问题中尝试解释的那样,Task。当您建议使用的所有
都是deadlocking@Thaoden:我已经更新了代码。我已经在没有死锁的情况下运行了这段代码。我同时执行了,并发现基本错误在由\u httpClient
调用的Web服务中。感谢您的帮助!
[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 "";
}