Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对于昂贵的IEnumerables,多线程程序不使用100%CPU_C#_.net_Multithreading_Ienumerable_Cpu Usage - Fatal编程技术网

C# 对于昂贵的IEnumerables,多线程程序不使用100%CPU

C# 对于昂贵的IEnumerables,多线程程序不使用100%CPU,c#,.net,multithreading,ienumerable,cpu-usage,C#,.net,Multithreading,Ienumerable,Cpu Usage,使用IEnumerables进行多线程处理时,不使用100%的CPU,IEnumerables并行计算多次,计算成本很高。示例是与Concat()组合的Aggregate()函数: 您的线程在clr.dll上被阻塞的事实!WKS::gc_heap::wait_for_gc_done表明垃圾收集器是应用程序的瓶颈。您应该尽可能地限制程序中堆分配的数量,以减少gc的压力 也就是说,还有另一种方法可以加快速度。默认情况下,在桌面上,GC配置为使用计算机上的有限资源(以避免减慢其他应用程序的速度)。如果

使用IEnumerables进行多线程处理时,不使用100%的CPU,IEnumerables并行计算多次,计算成本很高。示例是与Concat()组合的Aggregate()函数:


您的线程在
clr.dll上被阻塞的事实!WKS::gc_heap::wait_for_gc_done
表明垃圾收集器是应用程序的瓶颈。您应该尽可能地限制程序中堆分配的数量,以减少gc的压力


也就是说,还有另一种方法可以加快速度。默认情况下,在桌面上,GC配置为使用计算机上的有限资源(以避免减慢其他应用程序的速度)。如果你想充分利用现有资源,那么你可以。此模式假定您的应用程序是计算机上运行的最重要的东西。它将提供显著的性能提升,但会使用更多的CPU和内存。

为什么您认为它应该使用100%的CPU?10000个长度为1000000的字符串会消耗约20GB的内存。你能排除这个问题不是由于缺少可用物理内存而导致的页面错误吗?有趣的是,我无法从我的角度再现这个问题。NET 4.7.2,英特尔核心i7 5820K(12个vCore)。初始化非常慢,但是
并行。因为
实际使用了95%的CPU,您确定这是正确的重新编程代码吗?您指示
初始化-需要毫秒
,我需要几分钟。您的最后一个方法GenerateLongString()看起来可能会大量使用GC。用CPU密集但没有太多分配的东西替换它。我认为正确的建议是使用StringBuilder,String.Concat()会产生太多垃圾。@HansPassant
String.Concat(IEnumerable)
确实依赖StringBuilder。但是由于字符串的长度和数量是事先知道的,我想应该可以分配一个大小合适的StringBuilder来节省大量的分配。无论如何,在这个示例中有很多可能的优化,但我不知道OP试图运行的是“真正的”代码,还是仅仅是一个示例repro@HansPassant真正的代码没有String.Concat(),但它有许多IEnumerables操作(如GroupBy、OrderBy等)。repo代码只是最短的代码,我设法编写了它,它与原始代码有相同的问题。
// Initialisation.
// Each IEnumerable<string> is made so that it takes time to evaluate it
// everytime when it is accessed.
IEnumerable<string>[] iEnumerablesArray = ...  

// The line of the question (using less than 100% CPU):
Parallel.For(0, 1000000, _ => iEnumerablesArray.Aggregate(Enumerable.Concat).ToList());
class Program
{
    const int DATA_SIZE = 10000;
    const int IENUMERABLE_COUNT = 10000;

    static void Main(string[] args)
    {
        // initialisation - takes milliseconds
        IEnumerable<string>[] iEnumerablesArray = GenerateArrayOfIEnumerables();

        Console.WriteLine("Initialized");

        List<string> result = null;

        // =================
        // THE PROBLEM LINE:
        // =================
        // CPU usage of next line:
        //    - 40 % on 4 virtual cores processor (2 physical)
        //    - 10 - 15 % on 12 virtual cores processor
        Parallel.For(
            0, 
            int.MaxValue, 
            (i) => result = iEnumerablesArray.Aggregate(Enumerable.Concat).ToList());

        // just to be sure that Release mode would not omit some lines:
        Console.WriteLine(result);
    }

    static IEnumerable<string>[] GenerateArrayOfIEnumerables()
    {
        return Enumerable
              .Range(0, IENUMERABLE_COUNT)
              .Select(_ => Enumerable.Range(0, 1).Select(__ => GenerateLongString()))
              .ToArray();
    }

    static string GenerateLongString()
    {
        return string.Concat(Enumerable.Range(0, DATA_SIZE).Select(_ => "string_part"));
    }
}