我想知道使用链接到一个或多个ActionBlock的BufferBlock是否有好处,除了限制(使用BoundedCapacity),而不是直接发布到ActionBlock(只要不需要限制)。
答案 0 :(得分:19)
要添加到svick的答案,缓冲区块还有另一个好处。如果您有一个具有多个输出链接的块并希望在它们之间取得平衡,则必须将输出块转为非贪婪并添加缓冲区块来处理排队。我发现以下示例很有用:
引用现已死亡的链接:
这是我们计划做的事情:
注意,BufferBlock不会将输入数据的副本切换到它链接到的所有目标块。相反,它只对一个目标块执行此操作。我们期望当一个目标忙于处理请求时.It将被移交给另一个目标。现在让我们参考下面的代码:
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();
}
执行时会产生以下输出:
这表明只有一个目标实际上正在执行所有数据,即使它很忙(由于故意添加了Thread.Sleep(100))。为什么?
这是因为默认情况下所有目标块都是贪婪的,并且即使它们无法处理数据也会缓冲输入。为了改变这种行为,我们在DataFlowBlockOptions中将Greedy属性设置为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();
}
该程序的输出是:
这显然是按预期在三个ActionBlock中分布数据。
答案 1 :(得分:18)
如果您只想将项目从一个区块转发到其他区块,则不需要BufferBlock
。
但肯定会有一些有用的案例。例如,如果您有一个复杂的数据流网络,您可能希望从较小的子网络构建它,每个子网络都使用自己的方法创建。要做到这一点,你需要一些方法来表示一组块。在您提到的情况下,从方法返回单个BufferBlock
(可能为ITargetBlock
)将是一个简单的解决方案。
另一个BufferBlock
有用的示例是,您希望将项目从多个源块发送到多个目标块。如果您使用BufferBlock
作为中介,则不必将每个源块连接到每个目标块。
我确信还有很多其他例子可以使用BufferBlock
。当然,如果您没有看到任何理由在您的情况下使用它,那么请不要。
答案 2 :(得分:4)
不,第二个例子不会因为多种原因而编译:只能为“分组”数据流块设置greedy = false - 不能为执行块设置;然后它必须通过GroupingDataflowBlockOptions设置 - 而不是DataflowBlockOptions;然后将其设置为属性值“{Greedy = false}”而不是构造函数参数。
如果要限制动作块的容量,可以通过设置DataflowBlockOptions的BoundedCapacity属性的值来实现(尽管如OP所述,他们已经知道此选项)。像这样:
ndk-build.cmd -B V=1 APP_ABI=armeabi
del /f/q c:\AndroidStudioProjects\Test\Test\src\main\libs\arm64-v8a\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\armeabi\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\armeabi-v7a\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\mips\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\mips64\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\x86\libJPEGProcessing.so c:\AndroidStudioProjects\Test\Test\src\main\libs\x86_64\libJPEGProcessing.so >NUL 2>NUL
[armeabi] SharedLibrary : libJPEGProcessing.so
C:/Android/sdk/ndk-bundle/build//../toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe -Wl,-soname,libJPEGProcessing.so -shared --sysroot=C:/Android/sdk/ndk-bundle/build//../platforms/android-9/arch-arm -lgcc -gcc-toolchain C:/Android/sdk/ndk-bundle/build//../toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64 -no-canonical-prefixes -target armv5te-none-linux-androideabi -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -lc -lm -o c:/AndroidStudioProjects/Test/Test/src/main/obj/local/armeabi/libJPEGProcessing.so
[armeabi] Install : libJPEGProcessing.so => libs/armeabi/libJPEGProcessing.so
copy /b/y "c:\AndroidStudioProjects\Test\Test\src\main\obj\local\armeabi\libJPEGProcessing.so" "c:\AndroidStudioProjects\Test\Test\src\main\libs\armeabi\libJPEGProcessing.so" > NUL