【发布时间】:2017-12-04 22:55:36
【问题描述】:
我从某个我无法控制的地方得到IEnumerable<Task> tasks。我不知道这些任务是使用new Task、Task.Run 手动创建的,还是它们是异步方法调用async Task DoSomethingAsync() 的结果。
如果我这样做await Task.WhenAll(tasks),我可能会无限期挂起,因为可能有一项或多项任务没有开始。
我不能这样做tasks.ForEach(t => t.Start()),因为如果它来自异步方法调用(已经启动),我会得到一个 InvalidOperationException “Start may not be called on a promise-style task”。
我不能做await Task.WhenAll(tasks.Select(t => Task.Run(async () => await t))),因为每个t 仍然不能仅仅通过等待它来开始。
我认为解决方案与基于此检查每个任务的Status 和Start() 有关,但我也认为这可能很棘手,因为该状态随时可能改变,对吧?如果这仍然是要走的路,检查哪些状态是正确的,我应该担心哪些线程问题?
非工作案例示例:
//making an IEnumerable as an example, remember I don't control this part
Task t = new Task( () => Console.WriteLine("started"));
IEnumerable<Task> tasks = new[] {t};
//here I receive the tasks
await Task.WhenAll(tasks);//waits forever because t is not started
工作案例示例:
//calls the async function, starting it.
Task t = DoSomethingAsync();
IEnumerable<Task> tasks = new[] {t};
//here I receive the tasks and it will complete because the task is already started
await Task.WhenAll(tasks);
async Task DoSomethingAsync() => Console.WriteLine("started");
【问题讨论】:
-
从来没有什么好的理由去创建一个未启动的任务,当然你没有理由将一个未启动的任务暴露给任何其他代码。我会认为任何返回未启动任务的方法都是错误的。如果是您的代码,请修复它,如果是其他人的代码,请告诉他们他们有错误并且他们需要修复他们的代码。任何返回已启动和未启动任务的mix 的方法都是邪恶的。如果是您的代码,请修复它,如果是其他人的代码,请远离他们并且永远不要再触摸他们的代码,您不能相信它可以正常工作。
-
await Task.WhenAll(tasks.Select(t => Task.Run(async () => await t)))只是一种冗长、迂回且效率较低的写作方式await Task.WhenAll(tasks);没有理由写前者,除非你的 CPU 太冷并且你需要加热它. -
@Servy 很重要,我最终可能会简单地记录它期望已启动的任务,而不是尝试处理未启动的任务。
-
真的没有理由去记录它。您在任何地方编写或与之交互的任何代码都只会期望启动任务,并且永远不会尝试启动任务。每当您处理 TPL 时,它都是隐含的。
标签: c# asynchronous async-await task