【问题标题】:Dataflow(TPL) - exception handling issue?数据流(TPL) - 异常处理问题?
【发布时间】:2014-07-24 07:07:24
【问题描述】:

我不确定是我做错了什么还是 Dataflow 有问题,但是当Receive() 抛出异常时我无法解决。 当我运行这个测试时:

public class AsyncProblem
{
    [Fact]
    public void AsyncVsAwaiterProblem()
    {
        var max = 1000;
        var noOfExceptions = 0;
        for (int i = 0; i < max; i++)
        {
            try
            {
                Await().Wait();
            }
            catch
            {
                noOfExceptions++;
            }
        }
        Assert.Equal(max,noOfExceptions);
    }

    public async Task Await()
    {
        bool firstPassed = false;
        var divideBlock = new TransformBlock<int, int>((x) =>
        {
            if (firstPassed)
                throw new ArgumentException("error");
            firstPassed = true;
            return 0;
        });
        divideBlock.Post(2);
        divideBlock.Post(3); // this should cause failure;
        divideBlock.Complete();

        while (await divideBlock.OutputAvailableAsync())
        {
                var value = divideBlock.Receive(); // this should throw exception on second call
        }
        try
        {
            divideBlock.Completion.Wait();
        }
        catch
        {
        }
    }
}

我得到的结果不一致,第一次运行:

Xunit.Sdk.EqualExceptionAssert.Equal() Failure 
Expected: 1000 
Actual:  127

然后再次运行:

Xunit.Sdk.EqualExceptionAssert.Equal() Failure
Expected: 1000
Actual:   14

有人可以确认这不是“在我的机器上”唯一的问题吗?

要点:https://gist.github.com/plentysmart/1c2ed2e925cc3f690f61

【问题讨论】:

  • noOfExceptions 不是线程安全的。尝试使用Interlocked.Increment
  • 谢谢,但是这段代码是连续的 - Wait() 确保当前任务已经完成。

标签: c# async-await tpl-dataflow


【解决方案1】:

实际上,我认为这种混淆是由于OutputAvailableAsync 行为造成的。当不再有任何输出时,此方法将返回false

当一个块发生故障时(即,由于转换委托的异常),它将清除输入和输出缓冲区。这会导致OutputAvailableAsync 返回false

【讨论】:

  • 是的,看起来OutputAvailableAsync 有时会返回true 有时会返回false 用于错误块,只是不确定这是设计还是错误.你有同样不一致的行为吗?
  • 否;我看到的与OutputAvailableAsync 一致,一旦块出现故障,总是返回false。请记住,测试中存在竞争条件,因为TransformBlock 在线程池上运行其委托。因此,您看到的(少量)异常仅在TransformBlock 处理第一个输入并产生第一个输出时,所以OAA 返回true,但随后在调用Receive 之前出现块故障。如果块处理两个输入,则OAA 返回false
  • 我能够在另一台机器上重现该问题(速度快得多)。更难重现,但我仍然得到不一致的结果:Xunit.Sdk.EqualExceptionAssert.Equal() Failure Expected: 100000 Actual: 2 请注意,我必须将 max 更改为 100000 才能得到这个。
  • 我已经更新了gist。它运行的时间要长得多,但我每次都会遇到这个问题。
猜你喜欢
  • 1970-01-01
  • 2018-02-16
  • 2012-04-10
  • 2012-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多