我有一个测试,我想确保我将从async
方法获得每个线程的孤立结果。我的测试如下所示:
public async Task MyMethod_Concurrency_ReturnsIsolatedResultPerThread()
{
int expectedResult = 20;
var theMock = new Mock<IService>();
theMock.Setup(m => m.GetResult(It.IsAny<int>()))
.Callback(() => Thread.Sleep(10))
.Returns<int>(t => Task.FromResult(expectedResult));
var sut = new MyClass(30, theMock.Object);
var rs1 = new ManualResetEventSlim();
var rs2 = new ManualResetEventSlim();
var task1 = Task.Run(async () =>
{
expectedResult = 40;
await sut.MyMethod();
rs2.Set();
rs1.Wait();
Assert.AreEqual(expectedResult, sut.Result);
});
var task2 = Task.Run(async () =>
{
rs2.Wait();
expectedResult = 45;
await sut.MyMethod();
Assert.AreEqual(expectedResult, sut.Result);
rs1.Set();
});
var task3 = Task.Run(() => Assert.AreEqual(0, sut.Amount));
await Task.WhenAll(task1, task2, task3);
}
测试工作正常并成功通过。但是,如果不使用ManualResetEventSlim
,它也可以按预期工作。所以我的问题是这个例子中ManualResetEventSlim
的用法是什么?我真的很困惑吗?任何人都可以解释在我的测试中使用ManualResetEventSlim
或不使用它有什么区别?我该怎么做,以便我的测试不会在不使用ManualResetEvents
??
答案 0 :(得分:0)
Task.WhenAll()仅等待所有任务,直到运行完成。它会将结果排序以匹配任务对象的传递顺序,但它不会强制执行任何执行顺序,尽管所有任务始终以其发生的顺序在内部启动(请参阅source code)。如果您需要一个固定的执行订单,那么您必须自己处理,例如:使用WaitHandle,如ManualRestEvent或Semaphore或使用任务延续方法。
这意味着如果您的任务都在同一时间内运行(如您的示例中),则它们以相同的顺序启动并以相同的顺序完成。 但是,如果您的任务在不同时间执行,例如task1 - &gt; 2000毫秒和任务2 - &gt; 20 ms,比task2在task1之前很久就完成了。
或者当task1花费比task2更长的时间来访问 sut.MyMethod()的调用时,使用你的例子,结果不会相同。现在,如果您需要在task2之前完成task1,则需要控制流程。