TPL数据流缓冲区块<>消费者在WPF的主线程中工作

时间:2018-02-22 11:43:53

标签: c# tpl-dataflow

我有一个简单的生产者 - 消费者类,使用BufferBlock对象来发布从TPL Dataflow Docs改编的消息,我的问题是在WPF应用程序中使用它导致消费者在同一个主要文件中接收数据-thread,同时控制台应用程序在工作线程中执行它。这是我的代码:

public class DataflowProducerConsumer
{
    BufferBlock<int> _buffer;

    public DataflowProducerConsumer()
    {
        _buffer = new BufferBlock<int>();

        var consumer = UseBufferBlock(_buffer);
    }

    public void Produce(int number)
    {
        _buffer.Post(number);

        var actionBlock = UseActionBlock();
        actionBlock.Post(number);
    }

    public async Task UseBufferBlock(ISourceBlock<int> source)
    {
        while (await source.OutputAvailableAsync())
        {
            int data = source.Receive();

            // ...process data asyncron
            Console.WriteLine("BufferBlock-Thread {0} received: {1}", Thread.CurrentThread.ManagedThreadId, data);
        }
    }

    public ITargetBlock<int> UseActionBlock()
    {
        return new ActionBlock<int>(data =>
        {
            Console.WriteLine(string.Format("ActionBlock-Thread: {0} received: {1}", Thread.CurrentThread.ManagedThreadId, data));
        });
    }
}

在主要或点击事件中执行测试:

var obj = new DataflowProducerConsumer();
obj.Produce(19);

好吧,我将Post更改为SendAsync但没有成功。 ActionBlock部分运作良好。有什么不同?我做错了什么?

1 个答案:

答案 0 :(得分:1)

这与TPL DataFlow本身无关,而是与以下声明有关:

await source.OutputAvailableAsync()

await将捕获当前SynchronizationContext并将后续(等待之后的其余方法)发布到它。如果没有同步上下文(如在控制台应用程序中) - 它将继续发布到线程池线程。

WPF具有同步上下文,并且发布到其中的是发布到UI线程(如Dispatcher.BeginInvoke()),因此您所观察到的内容。

要防止捕获当前同步上下文(以及 - 始终将后续连续发布到线程池线程),请使用ConfigureAwait(false)

while (await source.OutputAvailableAsync().ConfigureAwait(false))
{
    int data = source.Receive();

    // ...process data asyncron
    Console.WriteLine("BufferBlock-Thread {0} received: {1}", Thread.CurrentThread.ManagedThreadId, data);
}

另请注意,有ReceiveAsync()方法,您可以使用(并等待)而不是同步Receive(),但这与相关问题无关。