C# TPL数据流缓冲块<&燃气轮机;使用者在WPF的主线程中工作

C# TPL数据流缓冲块<&燃气轮机;使用者在WPF的主线程中工作,c#,tpl-dataflow,C#,Tpl Dataflow,我有一个简单的producer-consumer类,使用BufferBlock对象发布改编自的消息,我的问题是在WPF应用程序中使用它会导致使用者在同一主线程中接收数据,而控制台应用程序在工作线程中执行数据。这是我的密码: public class DataflowProducerConsumer { BufferBlock<int> _buffer; public DataflowProducerConsumer() { _buffer =

我有一个简单的producer-consumer类,使用
BufferBlock
对象发布改编自的消息,我的问题是在WPF应用程序中使用它会导致使用者在同一主线程中接收数据,而控制台应用程序在工作线程中执行数据。这是我的密码:

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));
        });
    }
}

嗯,我将
Post
改为
SendAsync
,但没有成功。而
ActionBlock
部分运行良好。有什么区别?我做错了什么?

这与第三方物流数据流本身无关,而是与以下陈述有关:

await source.OutputAvailableAsync()
wait将捕获当前的
同步上下文
,并对其进行后续处理(wait之后的方法的其余部分)。若并没有同步上下文(比如在控制台应用程序中),它会将延续发布到线程池线程

WPF有同步上下文,向其发布就是向UI线程发布(如
Dispatcher.BeginInvoke()
),所以这就是您观察到的

要防止捕获当前同步上下文(因此-始终向线程池线程后置继续),请使用
ConfigureAwait(false)


另外请注意,还有一个
ReceiveAsync()
方法,您可以使用它(并等待)代替同步
Receive()
,尽管这与问题无关。

解释得很好!谢谢我想我需要更多地了解同步上下文;-)@alex555这是一个很好的来源,来自这个特性的作者之一:为什么不直接链接这些块呢?
await source.OutputAvailableAsync()
while (await source.OutputAvailableAsync().ConfigureAwait(false))
{
    int data = source.Receive();

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