表观BufferBlock.Post/Receive/ReceiveAsync种族/错误

时间:2012-04-09 03:00:40

标签: c# task-parallel-library async-await dataflow tpl-dataflow

交叉发布到http://social.msdn.microsoft.com/Forums/en-US/tpldataflow/thread/89b3f71d-3777-4fad-9c11-50d8dc81a4a9

我知道......我并没有真正使用TplDataflow来发挥它的最大潜力。 ATM我只是使用BufferBlock作为消息传递的安全队列,其中生产者和消费者以不同的速率运行。我看到一些奇怪的行为,让我难以理解如何 继续进行。

private BufferBlock<object> messageQueue = new BufferBlock<object>();

public void Send(object message)
{
    var accepted=messageQueue.Post(message);
    logger.Info("Send message was called qlen = {0} accepted={1}",
    messageQueue.Count,accepted);
}

public async Task<object> GetMessageAsync()
{
    try
    {
        var m = await messageQueue.ReceiveAsync(TimeSpan.FromSeconds(30));
        //despite messageQueue.Count>0 next line 
        //occasionally does not execute
        logger.Info("message received");
        //.......
    }
    catch(TimeoutException)
    {
        //do something
    }
}

在上面的代码中(它是2000行分布式解决方案的一部分),每100ms左右定期调用Send。这意味着项目PostmessageQueue为单位,每秒约10次。这已经过验证。但是,有时似乎ReceiveAsync在超时内没有完成(即Post没有导致ReceiveAsync完成)并且在30秒后引发TimeoutException。此时,messageQueue.Count已达数百个。这是出乎意料的。在发布速度较慢(1个帖子/秒)时也会出现此问题,并且通常在1000个项目通过BufferBlock之前发生。

因此,要解决此问题,我使用以下代码,它可以工作,但偶尔会在接收时导致1秒延迟(由于上面发生的错误)

    public async Task<object> GetMessageAsync()
    {
        try
        {
            object m;
            var attempts = 0;
            for (; ; )
            {
                try
                {
                    m = await messageQueue.ReceiveAsync(TimeSpan.FromSeconds(1));
                }
                catch (TimeoutException)
                {
                    attempts++;
                    if (attempts >= 30) throw;
                    continue;
                }
                break;

            }

            logger.Info("message received");
            //.......
        }
        catch(TimeoutException)
        {
            //do something
        }
   }

这看起来像TDF中的竞争条件,但我无法理解为什么在我以类似方式使用BufferBlock的其他地方不会发生这种情况。从ReceiveAsyncReceive的实验性更改无济于事。我没有检查,但我想孤立地看,上面的代码完美无缺。这是我在“TPL数据流简介”tpldataflow.docx中记录的模式。

我该怎么做才能深究这一点?是否有任何指标可能有助于推断正在发生的事情?如果我无法创建可靠的测试用例,我可以提供更多信息吗?

帮助!

1 个答案:

答案 0 :(得分:1)

斯蒂芬似乎认为以下是解决方案

  

var m =等待messageQueue.ReceiveAsync();

     

而不是:

     

var m =等待messageQueue.ReceiveAsync(TimeSpan.FromSeconds(30));

你能否证实或否认这一点?