跳过Dataflow TransformBlock中的项目

Eri*_* J. 17 .net c# task-parallel-library tpl-dataflow

TPL Dataflow提供TransformBlock转换输入,例如:

var tb = new TransformBlock<int, int>(i => i * 2);
Run Code Online (Sandbox Code Playgroud)

是否有可能不输出一些输入,例如,如果输入未通过某些验证测试?

var tb = new TransformBlock<InputType, OutputType>(i =>
{
    if (!ValidateInput(i))
    {
        // Do something to not output anything for this input
    }
    // Normal output
}
Run Code Online (Sandbox Code Playgroud)

如果那是不可能的,那么实现这一目标的最佳模式是什么?
像下面这样的东西?

BufferBlock<OutputType> output = new BufferBlock<OutputType>();

var ab = new ActionBlock<InputType>(i =>
{
    if (ValidateInput(i)) 
    {
        output.Post(MyTransform(i));
    }
}
Run Code Online (Sandbox Code Playgroud)

svi*_*ick 19

有几种方法可以做到这一点:

  1. 使用TransformManyBlock如乔恩建议,并返回一个包含1个或0项的集合.
  2. 使用TransformBlock一些表示"无值"的特殊值(例如null),然后使用LinkTo()with过滤器删除它们.您还必须链接TransformBlock到null块(DataflowBlock.NullTarget<T>())而不使用过滤器,以排除特殊值.
  3. 我会认为这是一个黑客的东西,但你也可以使用Task基于它的构造函数TransformBlock:Task.FromResult()当你想要返回一些东西null时使用,当你不想.例如:

    new TransformBlock<int, int>(i => i % 2 == 0 ? Task.FromResult(i * 2) : null)
    
    Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 8

我自己没有使用过DataFlow,但我认为你可以使用a TransformManyBlock,只需让每一步返回一个空集合或一个单独的项目.

var tmb = new TransformManyBlock<InputType, OutputType>(i =>
{
    if (!ValidateInput(i))
    {
        return Enumerable.Empty<OutputType>();
    }
    ...
    // Or return new[] { outputValue };
    return Enumerable.Repeat(outputValue, 1);
});
Run Code Online (Sandbox Code Playgroud)

您甚至可以将FilterBlock<T>其概括为只有一个过滤谓词,并通过适当的匹配(就像Where在LINQ中一样).您最初可以使用TransformManyBlock上述方法实现此功能,但之后可以提高效率.


VMA*_*Atm 6

一个有点老的问题,想在这里补充一点经验:你可以为你的数据引入一个BufferBlock代替ActionBlock,并使用LinkTo带有条件谓词的扩展方法,这样有效的值就会进入TransformBlock,无效的将被忽略。为了丢弃它们,您可以简单地使用NullTarget块,它只是忽略它接收到的数据。所以最终的代码可能是这样的:

var input = new BufferBlock<int>();
var tb = new TransformBlock<int, int>(i => i * 2);
var output = new BufferBlock<int>();

// valid integers will pass to the transform
input.LinkTo(tb, i => ValidateInput(i));

// not valid will be discarded
input.LinkTo(DataflowBlock.NullTarget<int>());

// transformed data will come to the output
tb.LinkTo(output);
Run Code Online (Sandbox Code Playgroud)

链接也可以调整一些DataflowLinkOptions其他LinkTo过载