gpt4 book ai didi

c# - 任务中的类似代码返回不同的状态代码

转载 作者:行者123 更新时间:2023-12-03 02:03:20 25 4
gpt4 key购买 nike

我从三个不同的任务中抛出一个 OperationCanceledException ,每个任务都有细微的差别,如下代码所示:

static async Task ThrowCancellationException()
{
throw new OperationCanceledException();
}

static void Main(string[] args)
{
var t1 = new Task(() => throw new OperationCanceledException());
t1.Start();
try { t1.Wait(); } catch { }

Task t2 = new Task(async () => throw new OperationCanceledException());
t2.Start();
try { t2.Wait(); } catch { }

Task t3 = ThrowCancellationException();

Console.WriteLine(t1.Status); // prints Faulted
Console.WriteLine(t2.Status); // prints RanToCompletion
Console.WriteLine(t3.Status); // prints Canceled
}

我的问题是:

为什么每个任务的状态不同?

我可以理解,标记有 async 的代码/lambda 和未标记 async 的 lambda 之间存在差异,但即使在 之间,状态也不同async lambda 和运行相同代码的 async 方法。

最佳答案

I could understand that there are differences between the code/lambdas marked with async and the lambda not marked with async but the status is different even between the async lambda and the async method running the same code.

这并不完全正确。

如果你仔细观察 new Task(async () => throw new OperationCanceledException()) ,你会发现它正在调用重载 new Task(Action action) (没有重载需要 Func<Task> )。这意味着它相当于传递 async void 方法,而不是 async Task 方法。

<小时/>

所以:

Task t2 = new Task(async () => throw new OperationCanceledException());
t2.Start();
try { t2.Wait(); } catch { }

编译后的结果如下:

private static async void CompilerGeneratedMethod()
{
throw new OperationCanceledException()
}
...
Task t2 = new Task(CompilerGeneratedMethod);
t2.Start();
try { t2.Wait(); } catch { }

这会从线程池中获取一个线程,并在其上运行 CompilerGeneratedMethod。当从 async void 方法内部抛出异常时,该异常会在适当的地方重新抛出(在本例中,它是在 ThreadPool 上重新抛出),但 CompilerGeneratedMethod 方法本身会立即返回。这会导致 Task t2 立即完成,这就是它的状态为 RanToCompletion 的原因。

那么异常是怎么回事呢?它即将导致您的申请失败!在 Console.ReadLine 的末尾粘贴 Main ,并在您有机会按 Enter 之前看到应用程序退出。

<小时/>

这个:

Task t3 = ThrowCancellationException();

非常不同。它不会尝试在线程池上运行任何内容。 ThrowCancellationException 同步运行,并同步返回包含 TaskOperationCanceledException 。包含 TaskOperationCanceledException 被视为 Canceled

<小时/>

如果您想在 ThreadPool 上运行 async 方法,请使用 Task.Run 。它有一个重载,需要 Func<Task> ,这意味着:

Task t2 = Task.Run(async () => throw new OperationCanceledException());

编译为如下内容:

private static async Task CompilerGeneratedMethod()
{
throw new OperationCanceledException();
}
...
Task t2 = Task.Run(CompilerGeneratedMethod);

这里,当 CompilerGeneratedMethod 在 ThreadPool 上执行时,它返回包含 TaskOperationCanceledException 。然后,任务机制将 Task t2 转换为 Canceled 状态。

<小时/>

顺便说一句,请避免 new Task ,如果您想在 ThreadPool 上显式运行方法,则更喜欢使用 Task.Run 。 TPL中有很多方法是在async/await之前引入的,与它一起使用时会很困惑。

关于c# - 任务中的类似代码返回不同的状态代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60113345/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com