单元测试似乎不允许parallel.foreach并行执行

时间:2018-08-22 14:58:49

标签: c# multithreading unit-testing parallel-processing xunit.net

我有一个C#单元测试(实际上是一个集成测试),它测试包含Parallel.ForEach循环的代码块。当此代码在调试模式下,本地或已部署的环境中运行时,并行性将按预期工作(约20秒内完成)。但是,当我的集成测试命中该代码段时,它们最终会超时(超过4分钟)。我的猜测是,在单元测试运行时,某种程度上并行特性被关闭了。我知道这不是硬件问题,因为同一台机器可以在调试时执行并行性,而在运行单元测试时则很慢。但是,我不知道单元测试的设置或配置会导致什么。

请注意,并行运行测试不是问题-由于其他限制,我们必须串行运行测试。这是在单个测试中,如果Parallel.ForEach的性能在调试(通过IIS localhost)或运行单元测试的同时运行,则在同一台计算机,同一代码块上的性能会有很大不同。

我们的单元测试框架是xUnit。我们使用TypeMock进行围绕静态调用的模拟,但尚未配置任何禁止线程化的东西。单元测试表明池中有32K +线程可用。我可以有一个单独的单元测试,显示它可以并行运行。

单元测试

[Fact]
public void AssertManyAssetsEnumerated()
{
    var args = new EnumerateArgs();
    args.FirstIndex = 0;
    args.LastIndex = 22263;
    args.FileName = LARGE_INDEX_ASSET_PREFIX;
    args.FullLibrarySearch = true;

    var stopwatch = new Stopwatch();
    var translators = new FilenameFieldTranslator();

    stopwatch.Restart();
    var assets = Services.AssetService.Enumerate(ScenarioBuilder.MasterAdminUser, args, translators);
    stopwatch.Stop();

    Assert.Equal(22263, assets.Count);

    var assetIDs = assets.Select(a => a.ID);
    Assert.Equal(assetIDs.Distinct(), assetIDs);

    var assetFileNames = assets.Select(a => a.FileName);
    Assert.Equal(assetFileNames.Distinct(), assetFileNames);

    Assert.Equal(PrependZerosAndCreateFileName(lower + 1), assets[0].FileName);
    Assert.Equal(PrependZerosAndCreateFileName(realUpper), assets.Last().FileName);

    //All asserts up to this point pass, only this time assertion fails
    var start = new TimeSpan(0, 0, 0);
    var maxTimespan = new TimeSpan(0, 0, 120);
    Assert.InRange(stopwatch.Elapsed, start, maxTimespan);
}

循环

public SearchResult RunSearch(IUser user, AssetCollection collection, Aggregations aggregations, FieldTranslators translators)
{
    if (!collection.IsLargeRequest)
    {
        return RunSingleSearch(user, collection, aggregations, translators);
    }

    var subquerySize = 1000;

    var subqueryCollections = new List<AssetCollection>();
    for (var i = collection.FirstIndex; i < collection.LastIndex; i += subquerySize)
    {
        var subqueryCollection = Clone(collection);
        subqueryCollection.FirstIndex = i;
        subqueryCollection.LastIndex = i + subquerySize;

        subqueryCollections.Add(subqueryCollection);
    }

    var results = new List<SearchResult>();
    var resultLock = new object();

    Parallel.ForEach(subqueryCollections, c =>
    {
        var result = RunSingleSearch(user, c, aggregations, translators);

        lock (resultLock)
        {
            results.Add(result);
        }
    });

    var overallResult = CombineResults(collection, results);

    return overallResult;
}

同样,我可以在同一台计算机上在Web应用程序中运行此代码,并且该代码会在20秒内针对该请求执行。在同一台计算机上以相同的代码在单元测试中执行相同的请求,这需要4分钟。关于可能会使其变慢的原因,我遇到了很多死胡同,但我只是不知道。

  • 由于TypeMock隔离器不喜欢它(至少使用它的方式),因此我们在xUnit测试套件中禁用了并行执行。我尝试再次启用它,但是它没有解决单元测试中的性能问题
  • 如前所述,我们使用TypeMock隔离器模拟某些静态调用。 (我看到的)我们还没有做任何事情来限制/更改线程和/或任务的并行执行工作方式。
  • 单元测试中的线程池有32K +个可用线程。
  • 单独的单元测试可以确认一个不同的Parallel.ForEach循环确实可以并行执行(看起来在我使用的机器上一次大约有10个线程)
  • 我们正在使用最新版本的xUnit Visual Studio运行程序(2.4.0)在Visual Studio 2017中运行单元测试

任何对调查事项的帮助或建议将不胜感激。

0 个答案:

没有答案
相关问题