正在等待任务.运行(NonAsyncMethod())会更好
本文关键字:更好 在等待 NonAsyncMethod 运行 任务 | 更新日期: 2023-09-27 18:24:59
让我们说,我有一个这样的调用:
await Task.Run(async() => SomeLongRunningNonAsyncMethod());
我的理解是,当调用SomeLongRunningNonAsyncMethod()时,该调用直到遇到等待时才会返回。但是SomeLongRunningNonAsyncMethod()中没有等待。
那么,这与直接SomeLongRunningNonAsyncMethod()调用相同吗?
我的理解是,当调用
SomeLongRunningNonAsyncMethod()
时,该调用直到遇到等待时才会返回。但在SomeLongRunningNonAsyncMethod()
中没有等待。
您需要区分传递给Task.Run
的delegate
和Task.Run
的实际执行
前者将在ThreadPool
线程内同步执行。您不需要使用async
关键字,因为您不等待给定委托内的任何异步操作。
当Task.Run
开始执行时,后者将达到其await
,并将控制权交还给调用方法,直到委托完成执行。
那么,这与直接SomeLongRunningNonAsyncMethod()调用相同吗?
没有。直接调用将在当前运行的线程上同步执行。您的代码在ThreadPool
线程上同步执行委托,同时调用Task.Run
的线程以非阻塞方式等待Task
的完成。
您的代码实际上应该是:
await Task.Run(SomeLongRunningNonAsyncMethod);
您的理解确实存在缺陷。
当代码执行到达await Task.Run
时,它将首先像往常一样执行Task.Run
(这将使方法在线程池上排队),然后立即返回。当Task.Run
内部的方法完成时,将在await
之后继续执行。
这是否有用在很大程度上取决于你的背景。例如,如果您从WinForms/WPF应用程序中的事件处理程序调用此函数,这确实是避免在执行某些后台工作时阻塞UI线程的好方法。如果您在web应用程序中这样做,那么您只是无端地导致线程切换和线程池线程。
如果您在Task.Run
中执行I/O,而不是CPU工作,则需要找到一个异步API来执行相同的I/O工作-这将为您保存在I/O请求完成时无论如何都会阻塞的线程。
一旦返回对Task.Run
的调用,await
关键字将导致控制权返回到调用方法。该调用返回"立即"(它只会使用当前任务调度程序来调度操作,而不是等待它完成)。一旦任务完成,await
行后面的代码将继续执行。