【问题标题】:What is the usage of ManualResetEvent or ManualResetEventSlim here?ManualResetEvent 或 ManualResetEventSlim 这里有什么用?
【发布时间】:2018-05-19 19:19:06
【问题描述】:

我有一个测试,我想确保从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就无法通过我的测试??

【问题讨论】:

  • hrm 让我们看看文档是怎么说的 msdn.microsoft.com/en-us/library/… 提供了一个精简版的 ManualResetEvent。嗯,让我们看看msdn.microsoft.com/en-us/library/… 是什么意思通知一个或多个等待线程发生了事件。嗯,如果它仍然不清楚,让我们看看代码是如何使用断点工作的 msdn.microsoft.com/en-us/library/5557y8b4.aspx
  • @TheGeneral 正如我所说,我的问题是:为什么我的测试通过了,即使没有使用ManualResetEventSlim。我已经阅读了您已经提到的所有链接,但是在这个测试中我对ManualResetEventSlim 感到困惑?另外我不知道为什么断点没有命中我的测试!
  • 那些 ManualResetEvents 在那里强制方法运行的顺序 - 虽然 - 我不知道为什么不简单地通过编写类似的东西来强制执行顺序:“await sut.MyMethod(); Assert. AreEqual(40, sut.Result); 等待 sut.MyMethod(); Assert.AreEqual(45, sut.Result);"您的测试在没有 ManualResetEvents 的情况下通过的原因是“巧合”
  • @johannes.colmsee 你能给我举个例子说明我该怎么做,这样我的测试就不会在没有ManualResetEvents的情况下通过吗??

标签: c# multithreading unit-testing asynchronous async-await


【解决方案1】:

Task.WhenAll() 只会等待所有任务运行完成。它将对结果进行排序以匹配任务对象的传递顺序,但它不强制执行任何顺序,尽管所有任务总是在内部按照它们发生的顺序启动(参见source code)。如果您需要一个固定的执行顺序,那么您必须自己处理它,例如通过使用像 ManualRestEvent 或 Semaphore 这样的 WaitHandle 或使用任务延续方法。

这意味着如果您的任务运行时间都一样短(如您的示例中),那么它们以相同的顺序开始并以相同的顺序完成。 但是如果您的任务在不同的时间执行,例如任务 1 -> 2000 毫秒和任务 2 -> 20 毫秒,任务 2 将在任务 1 之前完成。

或者当 task1 比 task2 花费更长的时间来调用 sut.MyMethod() 时使用您的示例,结果将不一样。现在,如果您需要 task1 在 task2 之前完成,您需要控制流程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多