c# - nUnit Assert.That委托(delegate)并发问题

标签 c# multithreading asynchronous nunit task-parallel-library

我的代码中遇到了一些暂时的死锁,无法理解它。

简单代码(我无法创建简单的调用链来重现 InvokeChangeEvent 中的代码)

[Test]
public async void Test()
{
    sut.InvokeChangeEvent("./foo.file");
    // Event is handled by an async handler chaining multiple await resulting in a file write

    // await Task.Delay(3000);

    Assert.That(() => Directory.GetFiles("some dir").Count(), Is.EqualTo(3).After(15000, 300));

}

我知道你们 (:D) 想要可执行代码,但我无法将其分割,因此我希望通过解释获得一些见解。

会发生什么:sut.InvokeChangeEvent 调用一个事件处理程序,该事件处理程序随后调用一个async 事件处理程序,然后该事件处理程序又调用一些async。链的末尾产生一个 Task.Run,它归结为写入 3 个文件。

上面的 Assert 是作为带有 After 的委托(delegate)实现的,它返回一个 DelayedConstraint 并且有一个非常大的最大时间(15 秒)和一个小的轮询间隔。

现在,当我调试代码时,InvokeChangeEvent 调用完全执行到最后一个 Task.Run,​​但是当 Task.Run 返回时,执行将返回到主线程,并且执行断言,进入“等待轮询” .

但是断言永远不会成功。当我调试问题时,总是在 Assert 委托(delegate)运行(并失败)之后处理 Task.Run 的返回。

我发现,当我在断言之前放置 await Task.Delay(3000); 时,代码就会正确执行。

正如前面提到的,测试中的系统有大量的等待和 Task.Runs 链接,我无法使用一些简单的可运行代码重现该问题。

我已经搜索了一段时间,但我无法弄清楚为什么 Task.Run (在不同的线程上执行)会陷入(临时)死锁,即使 DelayedConstraint 已允许主线程继续进行的显式轮询间隔。

看起来DelayedConstraint通过某种Thread.Sleep锁定了主线程。 await Task.Delay 不会,我知道这一点。让我困惑的是我已经检查过我总是执行 await (并且从不 Task.Result 等),因此期望在断言之前已写入文件已执行。

(注意:用 Thread.Sleep 代替 await Task.Delay 不起作用。)

通常,DelayedConstraint 用于确保文件系统已正确写入所有文件,因为我在文件系统处理文件时遇到了一些延迟。

我有一些感觉,async void 事件处理程序可能会造成我不理解的情况。

如果我设法创建一个简单的示例,我将更新线程。

最佳答案

与 VS2012 单元测试类比,尝试使用 async Task 签名而不是 async void 作为您的测试方法。这样,NUnit 应该能够跟踪挂起的任务状态并通过 Task.Exception 检查异常。

根据定义,async void 方法是一个即发即忘的概念。该方法立即返回(准确地说,是在其中第一个异步 await 时),然后无法处理其完成或其中可能抛出的任何错误。按原样,async void 方法 are only good for event handlers ,前提是在方法内使用 try/catch 处理异常。

关于c# - nUnit Assert.That委托(delegate)并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22205708/

相关文章:

c# - 如何在不创建新类的情况下将简单的 JSON 对象发送到 ASP.NET?

c# - XmlNode.SelectNodes 返回 0 个节点

c - 不知道长度的二维全局数组。最佳实践?

sql-server - 我可以将长时间运行的存储过程分布在多个 CPU 上吗?

javascript - 使用 Ajax 调用从函数返回值

javascript - VueJS - V-for 不会在数据更新后重新呈现,需要刷新页面才能看到更改

javascript - 同步调用异步 Javascript 函数

c# - C# 中的事件或 Lambda?

c# - 如何更改 ADS 中的组名 (sAMAccountName)?

c - 多个生产者和消费者共享一个资源——只有一个线程在运行