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.Run重载接受任务?

Task.Factory.StartNew 和 Task.Run

Parallel.ForEach 与 Task.Run 和 Task.WhenAll

如何启动并等待 Task 运行

CS0121'Task.Run之间的调用不明确 (Func键 )'和'Task.Run(Func )”

C# Task.Run()运行“含参数和返回值的方法”的用法