TPL 数据流 - ExecutionDataflowBlockOptions.SingleProducerConstrained

TPL Dataflow - ExecutionDataflowBlockOptions.SingleProducerConstrained

数据流库有这个我试图理解的选项:ExecutionDataflowBlockOptions.SingleProducerConstrained

我对其功能进行了测试。令我惊讶的是,它似乎会丢失消息。为什么这不会抛出异常而不是丢弃消息?

[TestMethod]
public void ExecutionDataflowOptions_SingleProducerConstrained()
{
    //The failure does not happen each time, so I run it a few times.
    for (int iter = 0; iter < 100; iter++) 
    {
        //Create two buffers and one action block.
        var buffer1 = new BufferBlock<int>();
        var buffer2 = new BufferBlock<int>();

        var input = new List<int>(); //A reference type, to be changed by the action block
        var transform = new ActionBlock<int>(i => input.Add(i)
            , new ExecutionDataflowBlockOptions() { SingleProducerConstrained = true });
        buffer1.LinkTo(transform);
        buffer2.LinkTo(transform);

        //Add two elements, one from each buffer
        buffer1.Post(1);
        buffer2.Post(2);
        Thread.Sleep(100); //added in test, see end

        //Violate the SingleProducerConstrained parameter
        Parallel.For(0, 100, i => //0, 1, 2 
        {
            var isAccepted1 = buffer1.Post(i);
            var isAccepted2 = buffer2.Post(i);
            if (!isAccepted1 || !isAccepted2)
                throw new Exception(); //This does not error.
        });

        //Ensure the transform completes (likely not necessary)
        transform.Complete();
        transform.Completion.Wait();

        //Account for all the items: 200 from the Parallel.For + 2 initial
        if (202 != buffer1.Count + buffer2.Count + transform.InputCount + input.Count)
            throw new Exception(); //Debug point
    }
}

这个标志的目的不是强制是否有一个生产者。相反。它用于优化,您只能在 you 声明只有一个生产者时才能进行优化,因此代码不需要强制执行。

设置此标志后,某些块可以删除锁定和同步代码及其开销。但前提是你要确保只有一个制作人。如果你不这样做,可能会出现竞争条件,你可能确实会丢失消息。

"This property should only be set to true if the code using the block can guarantee that it will only ever be used by one producer (e.g. a source linked to the block) at a time, meaning that methods like Post, Complete, Fault, and OfferMessage will never be called concurrently. Some blocks may choose to capitalize on the knowledge that there will only be one producer at a time in order to provide better performance."

来自ExecutionDataflowBlockOptions.SingleProducerConstrained Property