C# 应该返回任务<;T>;是否始终启动返回的任务?

C# 应该返回任务<;T>;是否始终启动返回的任务?,c#,task-parallel-library,C#,Task Parallel Library,如果我有这样的方法 Task<bool> LongProcessTaskAsync(); Task LongProcessTaskAsync(); 返回已启动的任务是更好的做法吗 return Task<bool>.Factory.StartNew(() => { ... }); 返回Task.Factory.StartNew(()=>{…}); 或者只返回新任务(()=>…) 就个人而言,我更喜欢第一种方法,但我更希望与其他API和库保持一致 返回未启动的

如果我有这样的方法

Task<bool> LongProcessTaskAsync();
Task LongProcessTaskAsync();
返回已启动的任务是更好的做法吗

return Task<bool>.Factory.StartNew(() => { ... });
返回Task.Factory.StartNew(()=>{…});
或者只返回新任务(()=>…)

就个人而言,我更喜欢第一种方法,但我更希望与其他API和库保持一致


返回未启动的任务是否更合适?

对于异步/等待方法,任务将已经启动。另外,为基于任务的版本添加的所有BCL方法都返回已启动的任务。不这样做会有点奇怪,因为现在常见的消费者案例是:

var foo = await GetFooAsync();
[EDIT]基于Stephen指出TAP指南涵盖了这一点(他已经包含了一个指南链接),我将引用第4页中的相关内容(在基于任务的异步模式定义->行为->任务状态中),并在关键部分添加了粗体+斜体

任务状态

Task类提供异步操作的生命周期,以及 该周期由TaskStatus枚举表示。为了 支持从Task和Task as派生的类型的角案例 以及施工与调度的分离,任务类 公开一个Start方法。由其公共构造函数创建的任务是 被称为“冷”任务,因为它们的生命周期始于 非计划任务状态。已创建状态,并且直到开始 对这些实例进行调度时调用。 所有其他任务的生命周期都以“热”状态开始,这意味着 它们所代表的异步操作已经启动 并且其TaskStatus是一个枚举值,而不是Created

从TAP方法返回的所有任务都必须是“热的”。如果是TAP方法 在内部使用任务的构造函数来实例化要执行的任务 返回时,TAP方法必须在 还它TAP方法的使用者可以安全地假设 返回的任务为“热”,不应尝试调用任何 从TAP方法返回的任务。对“热”任务调用Start将 导致InvalidOperationException(此检查已处理 由任务类自动执行)


詹姆斯·曼宁回答正确。这是另一个角度:为什么会有人想要一个未开始的任务?如果他这样做了,他可以等待调用该方法。他本可以晚些时候再打电话,或者自己把它包装在一个懒惰的未来里。几乎没有理由不返回已启动的任务。

+1。返回的
任务
应启动的状态。任何使用您的方法的
async
代码都会期望它被启动,特别是如果它遵循TAP命名准则(即以
async
结尾)。未启动的任务实际上仅由任务并行库代码使用。从TPL继承的其他
Task
API不应该在TAP代码中使用:
Task.Wait
Task.WaitAll
Task.WaitAny
Task.Result
——本质上就是处理阻塞的任何东西。@StephenCleary假设我调用
var myTask=doworksync()(不带wait),然后调用其他一些代码,如
var myOtherTask=domoreworksync()。然后我做了一些其他的事情,现在在结束我的方法之前,我需要确保这两个任务(异步启动)已经完成。我要么使用
Task.Wait(myTask,myOtherTask)
等待我的任务;等待我的任务。你是想说我的第一个选项不应该被使用,而是应该使用
await
(使用
ConfigureAwait(false)
),还是我误解了?@Alisson:如果是在方法的末尾,我会使用
await Task.whalll(myTask,myOtherTask)。ConfigureAwait(false)
。未启动的
任务可以在任何上下文中执行。因此,从理论上讲,您可以将未启动的
任务
用作执行上下文无关紧要的工作单元(即
任务调度器
由调用方决定)。然而,我从来没有见过有人在实践中这样做。好吧,从来没有想过。可能最好将TaskScheduler传递给调用的方法,这样它就可以决定是否要在其他TaskScheduler上执行它。