【发布时间】:2018-05-16 03:59:10
【问题描述】:
我正在尝试以最小的耦合设置一群工人,但我想使用 C# async 和任务。并非所有任务都是纯异步的(有些是完全同步的)。这样做的动机是我想创建一些执行业务逻辑的简单方法,并使用System.Threading.Tasks.Task API 将它们链接在一起以保留一些排序概念。基本上,我想创建第一个任务,注册一些延续,然后等待最终任务完成。
这是我构建的简单原型,只是为了看看我想做的事情是否有效:
void Main()
{
var worker = new Worker();
var work = worker.StartWork(1, 2000);
work.ConfigureAwait(false);
var final = work.ContinueWith(_ => worker.StartWork(2, 0))
.ContinueWith(ant => worker.StartWork(3, 1500));
var awaiter = final.ContinueWith(_ => Tuple.Create(_.Id, _.Status));
Console.WriteLine("\"final\" completed with result {0}", awaiter.Result);
Console.WriteLine("Done.");
}
// Define other methods and classes here
class Worker {
internal async Task StartWork(int phase, int delay) {
Console.WriteLine("Entering phase {0} (in Task {1}) with {2} milliseconds timeout.", phase, Task.CurrentId, delay);
if (delay > 0)
{
Console.WriteLine("Do wait for {0} milliseconds.", delay);
await Task.Delay(delay);
}
Console.WriteLine("ending phase {0}", phase);
}
}
问题似乎在awaiting等待所谓的awaiter任务:
Entering phase 1 (in Task ) with 2000 milliseconds timeout.
Do wait for 2000 milliseconds.
ending phase 1
Entering phase 2 (in Task 769) with 0 milliseconds timeout.
ending phase 2
Entering phase 3 (in Task 770) with 1500 milliseconds timeout.
Do wait for 1500 milliseconds.
"final" completed with result (770, RanToCompletion)
Done.
ending phase 3
这只是不支持吗?我以为我非常了解Task API,但显然我不了解。我认为我可以将其转换为不使用async 或任务,而只是完全同步地执行该方法,但这似乎是一种不好的做事方法。我想要运行的延续并不完全是这个(它们只接受CancellationToken)。任务之间的消息没有特别的依赖关系——我只需要保留一些排序的概念。
谢谢。
编辑:我在上面错误地使用了awaiting这个词:我知道访问Task.Result是完全同步的。我很抱歉。
编辑 2: 我预期会发生的是调用 ContinueWith(_ => worker.Start(2, 0)) 会将任务返回到 ContinueWith,当我的用户委托时,TPL 将在内部等待 worker.StartWork 返回的任务返回了一个任务。查看ContinueWith 的重载列表,这显然是不正确的。我试图解决的部分问题是如何等待安排工作的Main 方法;我不想在所有延续完成之前退出。
我使用ContinueWith 的动机是我有类似以下的要求:
- 主要方法分为三个阶段。
- 第 1 阶段创建三个工人:
a、b和c。 - 阶段 2 在完成任务
b和c后启动一个额外的工作人员d,在完成a和b后启动另一个工作人员e(依赖项是这些任务必须是按此顺序创建) - 在完成所有工作之前,将遵循与此类似的过程。
如果我正确理解 cmets 中的反馈,我基本上有两种方法可以做到这一点:
- 使方法同步,并自己注册延续。
- 保留标记为
async Task的方法,并使用await关键字和Task.WhenAllAPI 来安排延续。
【问题讨论】:
-
我认为查看文档的原因是因为我没有通过
TaskContinuationOptions.AttachedToParent,所以Task延续是在分离状态下创建的。有没有更熟悉的人能够偶然证实这一点? -
我很困惑为什么你会认为会发生其他事情。您已经创建了一个异步工作流,其中大部分任务都没有等待;正如我一直在说的那样:await 是异步工作流上的排序操作。您几乎没有进行任何排序,因此应该预料到并非所有内容都按顺序运行,对吧?
-
更清楚地说出您期望在这里发生的事情以及您期望它发生的原因,并且有人可以向您解释您的想法出错的地方。
-
你需要
await你的任务。ContinueWith也是老派,现在我们有await -
@EricLippert,我很抱歉;我认为这个问题很清楚。我已经更新了问题以试图澄清。感谢您的反馈。
标签: c# multithreading asynchronous