跳过Dataflow TransformBlock中的项目

时间:2012-10-31 17:56:57

标签: c# .net task-parallel-library tpl-dataflow

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

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:16)

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

  1. 使用{建议的TransformManyBlock并返回包含1或0项的集合。
  2. 使用TransformBlock表示“无值”的特殊值(例如null),然后使用带有过滤器的LinkTo()来删除这些值。您还必须在不使用过滤器的情况下将TransformBlock链接到空块(DataflowBlock.NullTarget<T>()),以排空特殊值。
  3. 我认为这是一种黑客行为,但你也可以使用基于Task的{​​{1}}构造函数:当你想要返回一些内容时使用TransformBlock { {1}}当你不这样做时。例如:

    Task.FromResult()

答案 1 :(得分:8)

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

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

您甚至可以将此概括为FilterBlock<T> 具有过滤谓词,并通过适当的匹配(就像LINQ中的Where一样)。您最初可以使用TransformManyBlock执行此操作,但之后会更高效。

答案 2 :(得分:1)

有点老问题,想在这里添加一些经验:你可以为你的数据引入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);

也可以使用DataflowLinkOptions {/ 3}来调整某些other LinkTo overload的链接。