如果有与使用链接到一个或多个ActionBlocks,比(使用BoundedCapacity)节流以外的BufferBlock相关的益处,我想知道的只是直接发布到ActionBlock(S),而不是(只要节流则不需要)。
Answer 1:
如果你想要做的就是转发从一个块到其他几个项目,你不需要BufferBlock
。
但也有肯定的地方是有用的情况。 举例来说,如果你有一个复杂的数据流的网络,您可能希望从较小的子网络构建它,在它自己的方法创建的每一个。 而要做到这一点,你需要一些方法来表示一组块。 在这种情况下,你所提到的,返回该单BufferBlock
(可能是因为ITargetBlock
从法)将是一个简单的解决方案。
其中另一个例子BufferBlock
将是有益的是,如果你想送几个源块项目的几个目标块。 如果使用BufferBlock
作为中介,你不必每个源块连接到每个目标块。
我敢肯定,有许多其他的例子,你可以使用BufferBlock
。 当然,如果你没有看到任何理由在你的情况来使用它,那就不要。
Answer 2:
为了增加svick的答案,有bufferblocks的另一个好处。 如果你有多个输出链接块,并希望他们之间的平衡,你必须把输出块非贪婪和添加bufferblock处理排队。 我发现下面的例子有用:
从一个链接,现在是死的报价:
这就是我们打算做的事:
- 一些代码块将使用它的POST(T t)的方法发布数据到BufferBlock。
- 此BufferBlock被链接到使用LinkTo吨BufferBlock的方法3个ActionBlock实例)。
请注意,BufferBlock不输入数据的不移交副本,它与to.Instead它这样一个目标块only.Here我们期待的是,当一个目标是忙于处理request.It将交由中的所有目标块在其他target.Now让我们参考下面的代码:
static void Main(string[] args)
{
BufferBlock<int> bb = new BufferBlock<int>();
ActionBlock<int> a1 = new ActionBlock<int>(a =>
{
Thread.Sleep(100);
Console.WriteLine("Action A1 executing with value {0}", a);
});
ActionBlock<int> a2 = new ActionBlock<int>(a =>
{
Thread.Sleep(50);
Console.WriteLine("Action A2 executing with value {0}", a);
});
ActionBlock<int> a3 = new ActionBlock<int>(a =>
{
Thread.Sleep(50);
Console.WriteLine("Action A3 executing with value {0}", a);
});
bb.LinkTo(a1);
bb.LinkTo(a2);
bb.LinkTo(a3);
Task t = new Task(() =>
{
int i = 0;
while (i < 10)
{
Thread.Sleep(50);
i++;
bb.Post(i);
}
}
);
t.Start();
Console.Read();
}
当被执行时它产生以下输出:
- 动作A1与值1执行
- 动作A1与值2执行
- 动作A1与值3执行
- 动作A1具有值4执行
- 动作A1具有值5执行
- 动作A1具有值6执行
- 动作A1与值7执行
- 动作A1具有值8执行
- 动作A1与值9执行
- 动作A1与值10执行
这表明,只有一个目标是实际执行中的所有数据,即使它忙(由于Thread.sleep代码(100)有意添加)。为什么?
这是因为所有的目标块默认情况下自然界中的贪婪,甚至缓冲输入时,他们没有能够处理data.To改变这种行为,我们已经在DataFlowBlockOptions贪婪属性设置为false,同时初始化ActionBlock如下图所示。
static void Main(string[] args)
{
BufferBlock<int> bb = new BufferBlock<int>();
ActionBlock<int> a1 = new ActionBlock<int>(a =>
{
Thread.Sleep(100);
Console.WriteLine("Action A1 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: 1,
cancellationToken: CancellationToken.None,
//Not Greedy
greedy: false));
ActionBlock<int> a2 = new ActionBlock<int>(a =>
{
Thread.Sleep(50);
Console.WriteLine("Action A2 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: -1,
cancellationToken: CancellationToken.None,
greedy: false));
ActionBlock<int> a3 = new ActionBlock<int>(a =>
{
Thread.Sleep(50);
Console.WriteLine("Action A3 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: -1,
cancellationToken: CancellationToken.None,
greedy: false));
bb.LinkTo(a1);
bb.LinkTo(a2);
bb.LinkTo(a3);
Task t = new Task(() =>
{
int i = 0;
while (i < 10)
{
Thread.Sleep(50);
i++;
bb.Post(i);
}
});
t.Start();
Console.Read();
}
这个程序的输出是:
- 动作A1与值1执行
- 行动A2与值3执行
- 动作A1与值2执行
- 行动A3与价值6执行
- 行动A3与价值7执行
- 行动A3与价值8执行
- 行动A2具有值5执行
- 行动A3值为9执行
- 动作A1具有值4执行
- 行动A2值为10执行
这清楚地跨预期3个ActionBlock(S)的数据的分布。
Answer 3:
否,第二个例子将不编译一些原因:它只能设定贪婪=假一个“分组”数据流块 - 用于执行块不; 然后它必须通过GroupingDataflowBlockOptions设置 - 不DataflowBlockOptions; 然后它被设置为属性值“{贪婪= FALSE}”不是一个构造符参数。
如果要限制动作框的能力,通过设置DataflowBlockOptions的BoundedCapacity属性的值(虽然作为OP说,他们已经意识到了这个选项)做到这一点。 像这样:
var a1 = new ActionBlock<int>(
i => doSomeWork(i),
new ExecutionDataflowBlockOptions {BoundedCapacity = 1}
);