Task.Run vs Task.Factory.StartNew - 预期的死锁没有发生。

问题描述 投票:0回答:1

我看了一下Task.Run和Task.Factory.StartNew的区别。

Task.Run(() => {});

应该相当于

Task.Factory.StartNew(() => {}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

但在我的代码中,我期望有一个死锁,但由于Task.Factory.StartNew的原因,死锁没有发生。

private Task backgroundTask;

private async Task DoSomethingAsync()
{
   // this should deadlock
   await this.backgroundTask.ConfigureAwait(false);
   throw new Exception();
}

private async Task Test()
{
   this.backgroundTask = Task.Factory.StartNew(async () =>
      {
         await this.DoSomethingAsync().ConfigureAwait(false);
      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

   // just wait here for testing/debugging
   await Task.Delay(10000).ConfigureAwait(false);
   // if no deadlock, this should throw
   await this.backgroundTask.ConfigureAwait(false);
}

但它并没有发生死锁 在DoSomethingAsync中的异常被抛出,但从未被捕获。在Task.Delay之后等待任务也没有抛出,因为它是RanToCompletion。

当使用Task.Run时,它是死锁的。

private Task backgroundTask;

private async Task DoSomethingAsync()
{
   // this is deadlocking
   await this.backgroundTask.ConfigureAwait(false);
   throw new Exception();
}

private async Task Test()
{
   this.backgroundTask= Task.Run(async () =>
      {
         await this.DoSomethingAsync().ConfigureAwait(false);
      });

   // just wait here for testing/debugging
   await Task.Delay(10000).ConfigureAwait(false);
   // never reached because of deadlock
   await this.backgroundTask.ConfigureAwait(false);
}

谁能解释一下这种行为?

c# async-await task deadlock
1个回答
5
投票

该方法 Task.Factory.StartNew 当与异步委托一起使用时,返回一个嵌套任务。Task<Task>. 你正在将这个嵌套任务分配给一个类型为 Task,这是被允许的,因为该类 Task<TResult> 派生 Task. 那么发生的事情就是你失去了对内心任务的参考,所以你没有办法等待它。当你 await this.backgroundTask 你在等待外边 Task<Task>,但你无法得到 await 操作的结果,这是一个 Task,内部 Taskawait 它。内心的任务已经变成了一个火烧眉毛的任务。

© www.soinside.com 2019 - 2024. All rights reserved.