C#:加权信号量-是否存在?

时间:2018-09-24 17:40:48

标签: c# elasticsearch asynchronous testing automation

TL; DR-在指定给定任务将占用更多资源的同时,我是否可以等待类似信号量的类,因为我当前的限制因素是两个不同数据源之间的数据审核中的内存使用情况(ElasticSearch和SQL Server)?

我正在编写一个基本的测试运行器应用程序,在该应用程序中,我使用单个静态方法定义测试类,该方法根据特定于该测试的一些通用配置信息实例化其自身的实例。我选择构建自己的测试运行器,而不是很久以前使用xUnit或nUnit,因为那些并行器可能无法满足我的需求,但是设计相似,因为我用Fact属性和测试标记了静态方法跑步者通过Activator.CreateInstance找到并执行它。

注意:所有带有“ Wrap”的类名都是在Singleton模式之后的静态实例,该模式包装了特定的共享资源,例如Logging或Configuration,以便我可以添加用于测试的属性。

public static int Main(string[] args)
{
        var testMethods = new List<ClassMethodInstance>();
        var returnCode = 0;
        Initialize();

        var test = typeof(FactAttribute);

        PopulateByAttribute(testMethods, test);

        var timer = Stopwatch.StartNew();
        var startDt = DateTime.Now;
        //Parallel.ForEach(GetSelectedTests(testMethods), RunClassMethodInstance); 
        GetSelectedTests(testMethods).AsyncAwaitAll(RunClassMethodInstance);

        Logger.Info($"Elapsed time: {timer.Elapsed}");

        try
        {
            Assert.Empty(FailedTests);
        }
        catch (Exception e)
        {
            Logger.Error(e.Message, e);
            returnCode = -1;
        }

        LogWrap.FlushQueue();
        LogWrap.SendEmail(startDt);

        return returnCode;
}

一种测试方法如下:

    [Fact]
    public static void ValidateElasticSearchState()
    {
        var options = new ParallelOptions{MaxDegreeOfParallelism = 4};

        var tests = from store in ConfigWrap.TestStores 
            from type in ValidTypes 
            where ConfigWrap.ElasticDocumentTestTypes.Contains(type)
            orderby store, type
            select new TestCase(type, store);

        Parallel.ForEach(tests, options, Process);
        //tests.AsyncAwaitAll(Process, TaskCreationOptions.LongRunning);
    }

一些背景信息:ClassMethodInstance只是我创建的一个类,目的是简化使用静态,实例和异步方法正确使用Activator.CreateInstance的代码量,PopulateByAttribute()是读取以下内容的方法在同一程序集中的每个方法的属性,并仅使用具有指定属性的方法填充提供的集合,然后使用GetSelectedTests()过滤器,这些过滤器仅由那些在Config文件中具有对应模式的方法设置为标记为True。

那么,我的问题适用于我的并行性方法。最初,使用静态方法是为了方便我使用Parallel.ForEach在计算机允许的范围内同时运行所有测试。通过学习,我学会了使用异步等待模式而不是Parallel.ForEach来更好地利用线程和操作,我创建了一个通用扩展方法,该方法将使用Task.Factory.StartNew通过异步模式运行代码。 C#。

要运行该操作而不需要结果:

public static void AsyncAwaitAll<T>(this IEnumerable<T> enumerable, Action<T> action, TaskCreationOptions options = TaskCreationOptions.None)
    {
        var tasks = enumerable
            .Select(item => Task.Factory.StartNew(() => action(item), options))
            .ToArray();

        Task.WaitAll(tasks);
    }

如果我需要结果:

public static T GetAwaitableResult<T>(this Task<T> task) =>
        task.GetAwaiter().GetResult();

public static TOutput[] AsyncReturnAll<TInput, TOutput>(this IEnumerable<TInput> enumerable, Func<TInput, TOutput> method, TaskCreationOptions options = TaskCreationOptions.None)
    {
        var tasks = enumerable
            .Select(item => Task.Factory.StartNew(() => method(item), options))
            .ToArray();

        return Task.WhenAll(tasks).GetAwaitableResult();
    }

我的问题是,我知道某些操作会占用大量内存,而另一些操作则重量很轻。我想拥有一个类似于信号量的类,我可以说一个操作将占用10个处理单元,而另一个操作将仅占用2个处理单元。我曾考虑过使用一个简单的int输入权重,然后在一个For-Loop上进行迭代以等待静态Semaphore实例,但是我冒着一个或多个操作的风险,即更高的权重阻止了该信号量,在此情况下任务可能比较轻能够进行其他处理。

我已经使用LongRunning作为一个选项,虽然它提供了帮助,但是它并不能完全解决问题,因为此应用程序中包括的数据审核会从两个数据存储中合并数据并将它们在内存中进行比较,并且在异步等待中,可能同时进行十次或更多次审核,其中Parallel.ForEach在我的计算机上不支持超过八次。但是,即使使用Parallel.ForEach,我也用光了内存,因为对足够大的测试集进行的操作将始终落在每个执行繁重操作的线程上,因为它们花费的时间最长。

0 个答案:

没有答案