NUnit的Assert.That代表的并发性问题 [英] nUnit Assert.That delegate concurrency issue

查看:227
本文介绍了NUnit的Assert.That代表的并发性问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到我的代码中一些临时锁死,不能换我的头周围。

I am experiencing some temporary dead lock in my code and can't wrap my head around it.

简单的代码(我不能创建一个简单的调用链重现在 InvokeChangeEvent

Simple code (I cannot create a simple call chain to reproduce the code in 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)希望。可执行代码,但我没能切下来,所以我希望通过解释一些有识之士

I am aware that y'all (:D) want executable code but I wasn't able to slice it down therefore I hope for some insight by explanation.

会发生什么: sut.InvokeChangeEvent 调用的事件处理程序后调用一个异步事件处理程序,然后调用一些异步。在链结果 Task.Run 归结为写3个文件的结尾。

What happens: sut.InvokeChangeEvent calls an event handler that later calls an async event handler which then calls some async. The end of the chain results in an Task.Run that boils down to write 3 files.

上面的断言实现与的委托后,返回一个 DelayedConstraint 键,具有非常大的最大时间(15秒)和小轮询间隔。

The Assert above is implemented as a delegate with After that returns a DelayedConstraint and has a very large max time (15 secs) and a small polling interval.

现在,当我调试InvokeChangeEvent通话完全执行到最后Task.Run代码但当Task.Run返回时,执行回产生主线程和断言执行进入等待与轮询。

Now when I debug the code the InvokeChangeEvent call is entirely executed to the last Task.Run but when the Task.Run returns, the execution is yielded back to the main thread and the Assert is executed entering the "wait with polling".

不过断言永远不会成功。当我调试问题Task.Run的回报总是处理的的断言委托已运行(失败)。

However the assert never succeeds. When I debug the issue the return of the Task.Run is always handled after the Assert delegate has run (and failed).

我已经想通了,那个时候我将等待Task.Delay(3000); 的断言之前,那么代码正确执行

I've figured out, that when I place an await Task.Delay(3000); before the Assert, then the code executes properly.

由于被测提到的所有系统有大量等待和Task.Runs链接,我无法重现该问题与一些容易执行的代码。

As mentioned the system under test has plenty await and Task.Runs chained and I was unable to reproduce the issue with some easy runnable code.

我已经被谷歌搜索有一段时间,我想不通为什么Task.Run(这是在不同的线程执行)产生的(暂时的)僵局,即使 DelayedConstraint 有一个明确的轮询间隔,使主线程进步。

I've been googling around for a while and I cannot figure out why the Task.Run (which is executed on a different thread) yield in a (temporary) deadlock even though the DelayedConstraint has an explicit polling interval to allow the main thread to progress.

它看起来像 DelayedConstraint 锁定在主线程通过某种 Thread.sleep代码的。 等待Task.Delay 不,我意识到这一点。什么混淆我的是我已签,我总是做一个等待(永不 Task.Result 等),因此。可以预料,断言已执行前该文件已被写入

It looks like the DelayedConstraint locks the main thread by some sort of Thread.Sleep. await Task.Delay does not, I am aware of that. What confuses me is I have checked that I always do an await (and never Task.Result, etc) and therefore would expect that the file has been written before the Assert has executed.

(注: Thread.sleep代码而不是等待Task.Delay 不起作用。)

(Note: Thread.Sleep instead of await Task.Delay does not work.)

通常 DelayedConstraint 用于确保文件系统已经正确地写入的所有文件,因为我经历过处理的文件的文件系统的一些延误。

Usually the DelayedConstraint is used to ensure that file system has properly written all files as I have experienced some delays of the file system dealing with files.

我有一些感觉,异步无效事件处理程序可以创建一个我不了解的情况。

I have some feeling that async void event handler may create a situation which I do not understand.

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

If I manage to create a simple sample, I will update the thread.

推荐答案

通过与VS2012单元测试的比喻,试图异步任务签名,而不是异步无效为您的测试方法。通过这种方式,NUnit的应通过 Task.Exception 能够跟踪挂起任务状态和检查异常。

By analogy with VS2012 unit testing, try async Task signature rather than async void for your test method. This way, NUnit should be able to keep track of the pending task status and inspect exceptions via Task.Exception.

异步无效法是一种发射后不管的概念,顾名思义。该方法返回瞬间(准确的说,在第一异步等待里面),再有就是没有办法处理其完成或里面可能引发的任何错误。由于是,异步无效 唯一的好事件处理程序的的,提供异常的方法中使用处理的try / catch

The async void method is a fire-and-forget concept, by definition. The method returns instantly (precisely, upon the first asynchronous await inside it), and then there is no way to handle its completion or any errors possibly thrown inside it. As is, async void methods are only good for event handlers, provided exceptions are handled within the method with try/catch.

这篇关于NUnit的Assert.That代表的并发性问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆