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