C# Task.WaitAll()死锁

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

我想在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);
    }
}
到底发生了什么

编辑:虽然这个问题被标记为重复问题,但我看不出链接的问题与这个问题有什么关系。链接中的代码示例都使用
.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 "";
}