gpt4 book ai didi

c# - 将动态创建的 ActionBlock 链接到 BufferBlock

转载 作者:太空狗 更新时间:2023-10-29 23:16:30 27 4
gpt4 key购买 nike

我不确定这是否可行,但如果可行,我可能做得不对。假设我有一个链接到许多消费者(ActionBlocks)的共享缓冲区。每个消费者都应该消费满足用于将其链接到缓冲区的谓词的数据。例如,ActionBlock1 应该消耗满足 x => x % 5 == 0 的数字, ActionBlock2 应该只消耗 x => x % 5 == 1等等

这是我得到的:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
var productionQueue = new BufferBlock<int>();

for (int i = 0; i < NumProductionLines; i++)
{
ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", i + 1, num));

productionQueue.LinkTo(productionLine, x => x % NumProductionLines == i);
}

return productionQueue;
}

然后我调用:

Random rnd = new Random();

ITargetBlock<int> temp = BuildPipeline(5);

while (true)
{
temp.Post(rnd.Next(255));
}

但是这不起作用。控制台中不显示任何输出。如果我修改 BuildPipeline方法为:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
var productionQueue = new BufferBlock<int>();

ActionBlock<int> productionLine1 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 1, num));
ActionBlock<int> productionLine2 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 2, num));
ActionBlock<int> productionLine3 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 3, num));
ActionBlock<int> productionLine4 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 4, num));
ActionBlock<int> productionLine5 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 5, num));

productionQueue.LinkTo(productionLine1, x => x % 5 == 0);
productionQueue.LinkTo(productionLine2, x => x % 5 == 1);
productionQueue.LinkTo(productionLine3, x => x % 5 == 2);
productionQueue.LinkTo(productionLine4, x => x % 5 == 3);
productionQueue.LinkTo(productionLine5, x => x % 5 == 4);

return productionQueue;
}

代码执行预期的操作。

有人可以阐明为什么动态创建和链接操作 block 不起作用吗?

附言如果我在 ITargetBlock<int> temp = BuildPipeline(5); 之后立即进入代码temp 确实显示有 5 个目标链接到缓冲区。而且每个target的Id都不一样。

提前致谢

编辑:添加了 svick 建议的更改,但仍然不好:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
var productionQueue = new BufferBlock<int>();
var opt = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 };

for (int i = 0; i < NumProductionLines; i++)
{
ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", i + 1, num));

int j = i;
productionQueue.LinkTo(productionLine, x => x % NumProductionLines == j);
}

ActionBlock<int> discardedLine = new ActionBlock<int>(num => Console.WriteLine("Discarded: {0}", num));
productionQueue.LinkTo(discardedLine);

return productionQueue;
}

现在只有第二条生产线处理数据(满足 x % 5 == 1 谓词的一条)。并且数据不满足谓词,这意味着我得到以 9 和 7 结尾的数字。

编辑:工作代码如下所示:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
var productionQueue = new BufferBlock<int>();
var opt = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 };

for (int i = 0; i < NumProductionLines; i++)
{
int j = i;
ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", j + 1, num));

productionQueue.LinkTo(productionLine, x => x % NumProductionLines == j);
}

productionQueue.LinkTo(DataflowBlock.NullTarget<int>());

return productionQueue;
}

最佳答案

问题是在您的第一个版本中,您对每个目标 block 使用相同的谓词。换句话说,谓词不依赖于 i

但即使这样做了,您的代码也不会工作,因为 i 变量在谓词之间共享,因此它们都将使用最后一个值。解决方法是将 i 复制到局部变量中并在谓词中使用它。

代码可能是这样的:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
var productionQueue = new BufferBlock<int>();

for (int i = 0; i < NumProductionLines; i++)
{
int iCopy = i;

ActionBlock<int> productionLine = new ActionBlock<int>(
num => Console.WriteLine("Processed by line {0}: {1}", iCopy + 1, num));

productionQueue.LinkTo(
productionLine, x => x % NumProductionLines == iCopy);
}

return productionQueue;
}

如果您问为什么您的代码不至少处理 x % 5 == 1 个数字,那是因为随机生成器可能会生成一个与该谓词不匹配的数字, 所以没有一个 ActionBlock 会接受它。因此,该号码将留在源 block 的输出队列中,其他号码将无法通过。

如果在您的实际代码中可能会发生类似情况,并且您想丢弃所有不符合任何谓词的数字,您可以将源代码块链接到 a block that does nothing并在将其链接到所有有用的 block 之后接受任何内容:

productionQueue.LinkTo(DataflowBlock.NullTarget<int>());

关于c# - 将动态创建的 ActionBlock 链接到 BufferBlock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12647185/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com