作为非专业人士,我正在尝试更好地了解.NET中可用的异步世界。Task.Run和ThreadPool.QueueUserWorkItem都允许在池线程上分派工作,但它们有什么区别或者如果您愿意,两者的优缺点是什么?
以下是我的优点列表。不确定是否完整或甚至正确。
ThreadPool.QueueUserWorkItem的优点:
- 可以传递参数
Task.Run的优点:
- 可以提供CancellationToken
- 可以等待Task完成
- 可以将返回值返回给调用代码
作为非专业人士,我正在尝试更好地了解.NET中可用的异步世界。Task.Run和ThreadPool.QueueUserWorkItem都允许在池线程上分派工作,但它们有什么区别或者如果您愿意,两者的优缺点是什么?
以下是我的优点列表。不确定是否完整或甚至正确。
ThreadPool.QueueUserWorkItem的优点:
Task.Run的优点:
ThreadPool.QueueUserWorkItem
只是一个旧的实现(在.NET 1.1中引入),与Task.Run
(在.NET 4.5中引入)执行相同的工作。
Microsoft试图避免在.NET中破坏向后兼容性。
在.NET 1.1编写的内容通常可以在.NET 4.5中编译和运行,而无需进行更改。
通常情况下,破坏性变化来自于编译器的更改,而不是框架的更改,比如在C# 5及更高版本中,在lambda内部使用foreach
声明的变量会表现出不同的行为。
当您拥有Task.Run
时,没有真正的理由使用ThreadPool.QueueUserWorkItem
。
最后要说的是:具有讽刺意味的是,事实上,通过HostingEnvironment.QueueBackgroundWorkItem(...)
,一切都已经回到了起点。
它允许您在ASP.NET环境中在后台线程上运行某些操作,并使Web服务器在长时间不活动期间通知后台工作关于AppDomain
关闭的情况。
我最近意识到 ThreadPool.QueueUserWorkItem
和 Task.Run
之间的一个区别是它们处理异常的方式。
如果在 ThreadPool.QueueUserWorkItem
中发生未处理的异常并且没有被全局异常处理程序处理,它将导致父线程崩溃。另一方面,从 Task.Run
线程中出现的未处理异常直到你使用 await
或 Task.Wait
才会传播。