NUnit的Assert.That代表的并发性问题 [英] nUnit Assert.That delegate concurrency issue
问题描述
我遇到我的代码中一些临时锁死,不能换我的头周围。
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屋!