.net - TPL数据流: creating a custom splitblock

标签 .net task-parallel-library tpl-dataflow

只需要一些帮助,借助数据流库创建自定义 splitblock,该数据流库是 .Net 中 TPL 的一部分。

我想要实现的是一个简单的自定义 block ,它接受输入并将其分割为多个转换 block 。这是过滤数据所必需的,我可以在其中记录负面条目并继续处理好的条目。

根据我的需要,将输入拆分为两个不同的输出应该足够了。类头应该看起来像这样......

public abstract class SplitBlock<TInput, TOutputLeft, TOutputRight>

我的问题是我真的不知道如何继续。我所知道的是我需要两个 TransformBlocks:

var leftBlock  = new TransformBlock<TInput, TOutputLeft>(...)
var rightblock = new TransformBlock<TInput, TOutputRight>(...)

在我所有的尝试中,我最终都有多个 ITargetBlocks 来存储左右 block 的输入,但这不可能是正确的,不是吗?

我很感谢您提供的每一个提示。

最佳答案

我会首先考虑该类的通用接口(interface)应该是什么样子。我认为最简单的解决方案是这样的:

public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
    public ITargetBlock<TInput> Input { get; }
    public ISourceBlock<TOutputLeft> LeftOutput { get; }
    public ISourceBlock<TOutputRight> RightOutput { get; }
}

这样,实现就很自然了:一个输入 block 连接到两个输出 block 。唯一的问题是实际处理是否应该在输出 block 中完成(就像您使用两个 TransformBlock 所建议的那样)还是在输入 block 中完成。

如果您想在输出 block 中进行处理,输入 block 可以是一个 ActionBlock,它将输入发送到两个输出,并且输出将是 TransformBlock,正如你所建议的。

public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
    private ActionBlock<TInput> input;
    private TransformBlock<TInput, TOutputLeft> leftOutput;
    private TransformBlock<TInput, TOutputRight> rightOutput;

    public ITargetBlock<TInput> Input { get { return input; } }
    public ISourceBlock<TOutputLeft> LeftOutput { get { return leftOutput; } }
    public ISourceBlock<TOutputRight> RightOutput { get { return rightOutput; } }

    public SplitBlock(
        Func<TInput, TOutputLeft> leftTransform,
        Func<TInput, TOutputRight> rightTransform)
    {
        input = new ActionBlock<TInput>(
            x =>
            {
                leftOutput.Post(x);
                rightOutput.Post(x);
            });
        leftOutput = new TransformBlock<TInput, TOutputLeft>(leftTransform);
        rightOutput = new TransformBlock<TInput, TOutputRight>(rightTransform);

        // TODO handle fault in input correctly
        input.Completion.ContinueWith(
            _ =>
            {
                leftOutput.Complete();
                rightOutput.Complete();
            });
    }
}

(这假设左变换和右变换可以同时处理相同的输入。)

另一方面,如果您想在输入 block 中执行处理(这对我来说更有意义),那么您可以将 ActionBlock 作为输入,并使用 BufferBlock 作为输出,输入 block 处理输入,然后将结果发送到输出 block :

public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
    private ActionBlock<TInput> input;
    private BufferBlock<TOutputLeft> leftOutput;
    private BufferBlock<TOutputRight> rightOutput;

    public ITargetBlock<TInput> Input { get { return input; } }
    public ISourceBlock<TOutputLeft> LeftOutput { get { return leftOutput; } }
    public ISourceBlock<TOutputRight> RightOutput { get { return rightOutput; } }

    public SplitBlock(
        Func<TInput, Tuple<TOutputLeft, TOutputRight>> combinedTransform)
    {
        input = new ActionBlock<TInput>(
            value =>
            {
                var result = combinedTransform(value);
                leftOutput.Post(result.Item1);
                rightOutput.Post(result.Item2);
            });
        leftOutput = new BufferBlock<TOutputLeft>();
        rightOutput = new BufferBlock<TOutputRight>();

        // TODO handle fault in input correctly
        input.Completion.ContinueWith(
            _ =>
            {
                leftOutput.Complete();
                rightOutput.Complete();
            });
    }

    public SplitBlock(
        Func<TInput, TOutputLeft> leftTransform,
        Func<TInput, TOutputRight> rightTransform)
        : this(x => Tuple.Create(leftTransform(x), rightTransform(x)))
    {}
}

关于.net - TPL数据流: creating a custom splitblock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18720870/

相关文章:

c# - 使用 ContinueWith 自继续任务

c# - TPL 数据流 : Why does EnsureOrdered = false destroy parallelism for this TransformManyBlock?

c# - 这是 .NET 4.5 的 WhenAll 的正确 .NET 4 实现吗?

c# - 什么时候不使用通用集合?

c# - 使用 C# 获取文件夹中包含大小的文件元数据的快速方法是什么?

c# - 如何在不使用 foreach 的情况下将 ArrayList 转换为强类型泛型列表?

c# - 我想等待抛出 AggregateException,而不仅仅是第一个异常

c# - BufferBlock 和 TPL 数据流行为

asp.net-core - 如何在 ASP NET Core 中集成 TPL 数据流

C#最快的2组排序数字的交集