meJ*_*rew 4 .net c# asynchronous task
我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
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
为什么每个任务的状态不同?
async我可以理解,标记为 的代码/lambda和未标记为 的 lambda之间存在差异,但即使在lambda 和运行相同代码的方法async之间,状态也是不同的。asyncasync
我可以理解,标记为异步的代码/lambda 和未标记为异步的 lambda 之间存在差异,但即使在异步 lambda 和运行相同代码的异步方法之间,状态也是不同的。
这不完全正确。
如果您仔细查看该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 { }
Run Code Online (Sandbox Code Playgroud)
这编译成类似:
private static async void CompilerGeneratedMethod()
{
throw new OperationCanceledException()
}
...
Task t2 = new Task(CompilerGeneratedMethod);
t2.Start();
try { t2.Wait(); } catch { }
Run Code Online (Sandbox Code Playgroud)
它从线程池中获取一个线程,并CompilerGeneratedMethod在其上运行。当从方法内部抛出异常时async void,该异常会在适当的地方重新抛出(在本例中,它是在 ThreadPool 上重新抛出),但方法CompilerGeneratedMethod本身会立即返回。这会导致Task t2立即完成,这就是其状态为 的原因RanToCompletion。
那么异常是怎么回事呢?它即将导致您的申请失败!Console.ReadLine在 的末尾粘贴 a Main,并在您有机会按 Enter 之前看到应用程序退出。
这:
Task t3 = ThrowCancellationException();
Run Code Online (Sandbox Code Playgroud)
是非常不同的。它不会尝试在线程池上运行任何内容。ThrowCancellationException同步运行,并同步返回Task包含OperationCanceledException. Task包含 an 的 A被OperationCanceledException视为Canceled。
如果要async在线程池上运行方法,请使用Task.Run. 这有一个重载,需要 a Func<Task>,这意味着:
Task t2 = Task.Run(async () => throw new OperationCanceledException());
Run Code Online (Sandbox Code Playgroud)
编译为类似:
private static async Task CompilerGeneratedMethod()
{
throw new OperationCanceledException();
}
...
Task t2 = Task.Run(CompilerGeneratedMethod);
Run Code Online (Sandbox Code Playgroud)
在这里,当CompilerGeneratedMethod在 ThreadPool 上执行时,它返回一个Task包含OperationCanceledException. 然后任务机制将 转变Task t2为Canceled状态。
顺便说一句,如果您想在 ThreadPool 上显式运行某个方法,请避免new Task使用 ,而更喜欢使用 using 。Task.RunTPL中有很多方法是在async/await之前引入的,并且在与它一起使用时会令人困惑。