【发布时间】:2014-08-01 14:04:29
【问题描述】:
我需要某种对象,其行为类似于广播块,但有保证的交付。所以我使用了来自this question 的答案。但我并不太清楚这里的执行流程。我有一个控制台应用程序。这是我的代码:
static void Main(string[] args)
{
ExecutionDataflowBlockOptions execopt = new ExecutionDataflowBlockOptions { BoundedCapacity = 5 };
List<ActionBlock<int>> blocks = new List<ActionBlock<int>>();
for (int i = 0; i <= 10; i++)
blocks.Add(new ActionBlock<int>(num =>
{
int coef = i;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ". " + num * coef);
}, execopt));
ActionBlock<int> broadcaster = new ActionBlock<int>(async num =>
{
foreach (ActionBlock<int> block in blocks) await block.SendAsync(num);
}, execopt);
broadcaster.Completion.ContinueWith(task =>
{
foreach (ActionBlock<int> block in blocks) block.Complete();
});
Task producer = Produce(broadcaster);
List<Task> ToWait = new List<Task>();
foreach (ActionBlock<int> block in blocks) ToWait.Add(block.Completion);
ToWait.Add(producer);
Task.WaitAll(ToWait.ToArray());
Console.ReadLine();
}
static async Task Produce(ActionBlock<int> broadcaster)
{
for (int i = 0; i <= 15; i++) await broadcaster.SendAsync(i);
broadcaster.Complete();
}
每个数字都必须按顺序处理,所以我不能在广播块中使用 MaxDegreeOfParallelism。但是所有接收到该数字的动作块都可以并行运行。
那么问题来了:
在输出中我可以看到不同的线程 ID。我是否正确理解它的工作原理如下:
在广播公司中执行await block.SendAsync(num);。
如果当前块尚未准备好接受该数字,则执行退出广播器并在 Task.WaitAll 处挂起。
当 block 接受数字时,广播器中的 foreach 语句的其余部分在线程池中执行。
直到最后都一样。
foreach 的每次迭代都在线程池中执行。但实际上它是按顺序发生的。
我的理解是对还是错? 如何更改此代码以异步将号码发送到所有块?
为了确保如果其中一个块目前还没有准备好接收号码,我不会等待它,所有其他准备好的人都会收到号码。并且所有块都可以并行运行。并保证交货。
【问题讨论】:
标签: c# multithreading task-parallel-library async-await tpl-dataflow