Async方法在无后续await时异常让出线程控制权的问题咨询
问题核心原因分析
你的核心误区是错误假设了ActualAsyncTask的所有执行逻辑都和Task.Run的匿名lambda跑在同一个线程上,实际二者在await完成后是跑在不同的线程池线程上的,具体调度逻辑如下:
- async方法的执行分为两段:碰到第一个未完成的await之前,所有代码同步运行在调用方线程(也就是
Task.Run分配的工作线程);碰到未完成的await后,当前线程会立即返回调用方,继续执行匿名lambda后续的循环逻辑。
你代码里await Task.Delay(1000)返回的是未完成的任务,所以1秒的等待开始后,线程直接回到匿名lambda,开始执行判断task2是否完成的死循环,同时监听取消请求。 - 控制台应用的默认同步上下文(
SynchronizationContext)为null,await完成后的后续代码不会回到原始调用线程,而是会被调度到线程池的任意空闲工作线程执行。也就是说ActualAsyncTask里的for循环、忙等、打印tick的逻辑,都是跑在另一个独立的线程池线程上的,和匿名lambda的循环逻辑本来就是并行执行的,所以取消请求可以被匿名lambda正常检测到并抛出异常。 - 当你完全移除await语句后,
ActualAsyncTask会变成纯同步方法,调用时会阻塞当前Task.Run的工作线程,跑完所有100次忙等和打印逻辑后才会返回到匿名lambda,根本没有机会执行取消检测的代码,自然无法响应取消请求。
你可以在两处添加Console.WriteLine(Thread.CurrentThread.ManagedThreadId)打印线程ID验证:一处加在匿名lambda的while循环内,一处加在ActualAsyncTask的for循环内,会看到两个ID完全不同,即可验证二者并非跑在同一个线程上。
内容的提问来源于stack exchange,提问作者CodeMolester66
相关产品推荐
相关产品推荐

