TPL Dataflow管道在服务中不断运行

时间:2017-01-02 19:20:26

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

例如,我有三个街区:

       Buffer -> Transform -> Action 

我正在运行webapi服务,它将请求中的数据带到缓冲区块。如何创建这样一个将永远运行的管道,而无需在Action块中调用Completion()并停止整个管道。

2 个答案:

答案 0 :(得分:4)

Dataflow没有一个很好的解决方案来获取某个输入的管道输出(因为它支持的不仅仅是简单的管道)。

你可以做些什么来创建一个TaskCompletionSource<T>并将其与输入一起发送到管道。管道中的每个块都将其发送到下一个块,最后一个块调用其SetResult()

然后,将输入发送到管道的代码可以await TaskCompletionSource的{​​{1}}来等待管道的输出。

答案 1 :(得分:3)

如果您需要在应用程序的生命周期内保留管道,而不仅仅是请求,您可以使用静态类来保存它。没有必要在动作块上调用完成。根据您的需求,另一个选择是分离应用程序和处理管道。这些可以由数据库消息队列分开,也可以由单独的服务器端应用程序分隔。

@svick使用TaskCompletionSource确定管道何时完成特定项目有一个好处。将所有内容放在一起这是一个可能有用的快速示例:

public class Controller {

    public async Task<int> PostToPipeline(int inputValue) {
        var message = new MessageIn(inputValue);
        MyPipeline.InputBuffer.Post(message);
        return await message.Completion.Task;
    }
}

public class MessageIn {
    public MessageIn(int value) {
        InputValue = value;
        Completion = new TaskCompletionSource<int>();
    }

    public int InputValue { get; set; }
    public TaskCompletionSource<int> Completion { get; set; }
}

public class MessageProcessed {
    public int ProcessedValue { get; set; }
    public TaskCompletionSource<int> Completion { get; set; }
}

public static class MyPipeline {

    public static BufferBlock<MessageIn> InputBuffer { get; private set; }
    private static TransformBlock<MessageIn, MessageProcessed> transform;
    private static ActionBlock<MessageProcessed> action;

    static MyPipeline() {
        BuildPipeline();
        LinkPipeline();

    }

    static void BuildPipeline() {
        InputBuffer = new BufferBlock<MessageIn>();

        transform = new TransformBlock<MessageIn, MessageProcessed>((Func<MessageIn, MessageProcessed>)TransformMessage, new ExecutionDataflowBlockOptions() {
            MaxDegreeOfParallelism = Environment.ProcessorCount,
            BoundedCapacity = 10
        });

        action = new ActionBlock<MessageProcessed>((Action<MessageProcessed>)CompletedProcessing, new ExecutionDataflowBlockOptions() {
            MaxDegreeOfParallelism = Environment.ProcessorCount,
            BoundedCapacity = 10
        });
    }

    static void LinkPipeline() {
        InputBuffer.LinkTo(transform, new DataflowLinkOptions() { PropagateCompletion = true });
        transform.LinkTo(action, new DataflowLinkOptions() { PropagateCompletion = true });
    }

    static MessageProcessed TransformMessage(MessageIn message) {
        return new MessageProcessed() {
            ProcessedValue = message.InputValue++,
            Completion = message.Completion
        };
    }

    static void CompletedProcessing(MessageProcessed message) {
        message.Completion.SetResult(message.ProcessedValue);
    }
} 

有几种方法可以协调管道中特定作业的完成;等待完成源可能是满足您需求的最佳方法。