Task.Run(()=> DoWorkAsync()) 和 new Thread(async()=> DoWorkAsync()); 的区别
Posted
技术标签:
【中文标题】Task.Run(()=> DoWorkAsync()) 和 new Thread(async()=> DoWorkAsync()); 的区别【英文标题】:Difference between Task.Run(()=> DoWorkAsync()) and new Thread(async()=> DoWorkAsync()); 【发布时间】:2021-12-29 06:16:14 【问题描述】:我最近遇到了一些让我很困惑的代码,我一直认为你必须使用线程或异步任务,而不是在它们之间混搭,
public async Task DoWork()
Task.Delay(1000);
现在我看到代码是这样调用的:
public void Main()
var thread = new Thread(async () => await DoWorkAync(); )
Priority = ThreadPriority.Highest,
IsBackground = true
;
// Start thread
proccessThread.Start();
现在这神奇地似乎没有在每次运行时创建一个线程,它似乎正在使用ThreadPool
。
现在我很难理解的是上述和以下之间的区别:
public void Main()
var task = Task.Run(DoWorkASync);
从我的测试来看,似乎 C# 线程在传入异步表达式与运行的标准方法时具有不同的功能>
【问题讨论】:
这很令人困惑,因为每个 sn-p 本身都是错误的。首先,没有等待。在第二个中,启动了与创建的线程不同的线程,在第三个中再次启动:不等待任务完成。Thread
构造函数不知道async
,因此线程将启动异步任务并立即完成,而无需等待异步处理完成。
There Is No Thread
【参考方案1】:
这个结构:
var thread = new Thread(async () => await DoWorkAync(); );
// Start thread
proccessThread.Start();
调用Thread
构造函数重载接受ThreadStart
委托,而ThreadStart
委托是() => void
。所以你有这个:
var thread = new Thread(StuffYourThreadExecutes);
thread.Start();
static async void StuffYourThreadExecutes()
await DoWorkAsync();
因此,您启动新线程并运行代码,直到第一个异步操作开始。然后线程存在。在第一个异步操作完成之后 - 其余的在任何线程任务调度程序提供程序(通常是线程池线程)上执行。在此过程中发生的任何异常都无法观察到。
例如,如果DoWorkAsync
类似于:
static async Task DoWorkAsync()
await Task.Delay(1000);
然后线程启动并几乎立即退出,没有做任何有用的事情。
Task.Run
,在那里传递异步委托时,执行文档中所述的操作:
将指定的工作排入队列以在线程池上运行并返回一个 任务的代理
所以整个操作只是在线程池线程上运行,而不是白白创建线程。您可以通过等待Task.Run
返回的任务来观察异常。
【讨论】:
谢谢这是有道理的,所以如果我理解正确,正确的方法是使用Task.Run()
方式而不是新线程方式。
是的,新线程方式这样使用首先是没用的,其次是危险的,因为你甚至无法观察到异常。
@Zapnologica 正确的做法是直接调用DoWorkAsync
;没有new Thread
,也没有Task.Run
。除非你有一个 UI 线程,并且 DoWorkAsync
做了足够多的同步工作来影响 UI 响应能力。在这种情况下,使用Task.Run
将工作卸载到线程池。
“在这个过程中发生的任何异常都无法观察到。”:这句话有点含糊。人们可能会将 notobserved 解释为 fire-and-forget,但事实并非如此。在async void
方法启动时捕获的同步上下文中重新抛出async void
方法中引发的异常,这会导致进程崩溃(在大多数情况下)。以上是关于Task.Run(()=> DoWorkAsync()) 和 new Thread(async()=> DoWorkAsync()); 的区别的主要内容,如果未能解决你的问题,请参考以下文章
Task.Factory.StartNew 和 Task.Run
Parallel.ForEach 与 Task.Run 和 Task.WhenAll