DataflowEx永远不会完成

时间:2017-12-26 16:39:40

标签: c# tpl-dataflow

我正在尝试将开源lib DataflowEx与下一个Dataflow声明一起使用。

class RequestClientFlow :Dataflow<string>{
    private readonly ILogger _logger;
    private readonly Dataflow<string, WebProxy> _webproxyDataflow;
    private readonly Dataflow<WebProxy, HttpClient> _httpClientDataflow;

    public RequestClientFlow(ILogger logger) : this(DataflowOptions.Default){
        _logger = logger;
    }

    public Dataflow<WebProxy, HttpClient> HttpClientDataflow => _httpClientDataflow;

    public RequestClientFlow(DataflowOptions dataflowOptions) : base(dataflowOptions){
        _webproxyDataflow = new TransformBlock<string,WebProxy>(s => {
            _logger.WriteLine("aaaa");
            return new WebProxy();
        }).ToDataflow();
        _httpClientDataflow = new TransformBlock<WebProxy,HttpClient>(proxy => {
            _logger.WriteLine("bbbb");
            return new HttpClient();
        }).ToDataflow();
        _webproxyDataflow.LinkTo(_httpClientDataflow);
        RegisterChild(_webproxyDataflow);
        RegisterChild(_httpClientDataflow);
    }

    public override ITargetBlock<string> InputBlock => _webproxyDataflow.InputBlock;
}

当我像

那样消费它时
var requestClientFlow = new RequestClientFlow(this);
requestClientFlow.Post("");
requestClientFlow.Complete();
await requestClientFlow.InputBlock.Completion;

它完成,我的输出显示

  

18:32:54.3773 | aaaa 18:32:54.3773 | bbbb

     

1传递,0失败,0跳过,耗时1.45秒(xUnit.net 2.3.1   建立3858)。

但是我的理解来自框架文档,我也应该能够使用

    requestClientFlow.Complete();
    await requestClientFlow.CompletionTask;

甚至

await requestClientFlow.SignalAndWaitForCompletionAsync();

它没有完成。有人可以帮我理解我做错了吗?

1 个答案:

答案 0 :(得分:1)

由于最后一个块是TransformBlock,您的流量无法完成。在您的第一个示例中,您await完成输入块,实际上已完成。 输出块无法完成,因为其输出缓冲区中的项目无处可去。 DataflowEx库在流程的最后一个块上正确awaiting。您可以在结尾添加ActionBlockNullTarget以实现完成。

DataflowEx而言,最终的流程应该是非常重要的

public interface IDataflow<in TIn> : IDataflow
{
    ITargetBlock<TIn> InputBlock { get; }
}

正如图书馆github页面上的示例所示:

public class AggregatorFlow : Dataflow<string>
{
    //...//

    public AggregatorFlow() : base(DataflowOptions.Default)
    {
        _splitter = new TransformBlock<string, KeyValuePair<string, int>>(s => this.Split(s));
        _dict = new Dictionary<string, int>();

        //***Note The ActionBlock here***
        _aggregater = new ActionBlock<KeyValuePair<string, int>>(p => this.Aggregate(p));

        //Block linking
        _splitter.LinkTo(_aggregater, new DataflowLinkOptions() { PropagateCompletion = true });

        /* IMPORTANT */
        RegisterChild(_splitter);
        RegisterChild(_aggregater);
    }

    //...//
}