Task.Run() 与创建 Task 实例然后 Start() 一样吗?

Posted

技术标签:

【中文标题】Task.Run() 与创建 Task 实例然后 Start() 一样吗?【英文标题】:Is Task.Run() the same as creating Task instance and then Start() it? 【发布时间】:2016-04-07 18:50:55 【问题描述】:

这是我一直使用的:

var task = Task.Run(DoSomething);

我想知道如果我改用这个是否会有所作为:

var task = new Task(DoSomething);
task.Start();

MSDN 说:

而不是调用这个构造函数,最常见的方法是 实例化一个任务对象并启动一个任务是通过调用静态 任务.运行(动作)

在第一种情况下,任务立即启动。这是一个明显的区别,但除此之外,我不清楚是否存在任何(相关)差异。

MSDN 没有说明使用的选项是否相同。 对于Task.Run() 他们document 它将使用DenyChildAttach 并且它将使用默认调度程序。

但是对于Start(),有no word 关于它使用的创建选项。

但还有另一个区别:Start() 将使用 current 任务调度程序而不是 默认 任务调度程序。

根据这里的answer,current 与 default 不同,并且 current 不应该与 async/await 结合使用,但是我必须承认我并不完全理解两者之间的区别并想知道在决定 Start()Task.Run() 时是否重要。

长话短说:看到差异,我想知道它们在与 async/await 结合使用时是否相关?如果它们是相关的,那是为什么呢? MSN 文档只说我可能想使用Task.Run(),但他们没有解释为什么

【问题讨论】:

你有什么问题?您已经发现了许多差异,注意到 Task.Run 适合异步代码,而 Start 不适合。 @StephenCleary 我将问题更新为更清晰。我可以看到差异,但我不知道它们如何/为什么重要。 【参考方案1】:

StartNew 类似于带有Task.Start 的任务构造函数。我有一篇博文详细介绍了major problems of StartNew,两者都适用于任务构造函数和Task.Start。特别是构造函数不理解异步委托,Start 默认使用当前调度器而不是默认调度器。

我还有一个blog series(还没有完成,抱歉!)详细介绍了所有Task 成员(和相关类型),讨论了哪些在哪些情况下最适合使用。有趣的是,Task 构造函数 (discussion) 或 Task.Start (discussion) 根本没有用例。总会有更好的解决方案。

【讨论】:

“StartNew 类似于带有 Task.Start 的任务构造函数” - 这是很好的信息。我阅读了所有关于StartNew() 的缺点。

以上是关于Task.Run() 与创建 Task 实例然后 Start() 一样吗?的主要内容,如果未能解决你的问题,请参考以下文章

Task.Factory.StartNew 和 Task.Run 到底有什么区别?

Task.Run 中的异步 lambda 与常规 lambda [重复]

C#:后台工作/通信的设计模式,不滥用Task.Run

Task.Run 和Task.Factory.StartNew 区别

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?

Task.Run() 代码是不是异步执行?