Should I always use Parallel.Foreach because more threads MUST speed up everything?

后端 未结 8 561
别那么骄傲
别那么骄傲 2020-12-05 04:27

Does it make sense to you to use for every normal foreach a parallel.foreach loop ?

When should I start using parallel.foreach, only iterating 1,000,000 items?

8条回答
  •  余生分开走
    2020-12-05 04:58

    These are my benchmarks showing pure serial is slowest, along with various levels of partitioning.

    class Program
    {
        static void Main(string[] args)
        {
            NativeDllCalls(true, 1, 400000000, 0);  // Seconds:     0.67 |)   595,203,995.01 ops
            NativeDllCalls(true, 1, 400000000, 3);  // Seconds:     0.91 |)   439,052,826.95 ops
            NativeDllCalls(true, 1, 400000000, 4);  // Seconds:     0.80 |)   501,224,491.43 ops
            NativeDllCalls(true, 1, 400000000, 8);  // Seconds:     0.63 |)   635,893,653.15 ops
            NativeDllCalls(true, 4, 100000000, 0);  // Seconds:     0.35 |) 1,149,359,562.48 ops
            NativeDllCalls(true, 400, 1000000, 0);  // Seconds:     0.24 |) 1,673,544,236.17 ops
            NativeDllCalls(true, 10000, 40000, 0);  // Seconds:     0.22 |) 1,826,379,772.84 ops
            NativeDllCalls(true, 40000, 10000, 0);  // Seconds:     0.21 |) 1,869,052,325.05 ops
            NativeDllCalls(true, 1000000, 400, 0);  // Seconds:     0.24 |) 1,652,797,628.57 ops
            NativeDllCalls(true, 100000000, 4, 0);  // Seconds:     0.31 |) 1,294,424,654.13 ops
            NativeDllCalls(true, 400000000, 0, 0);  // Seconds:     1.10 |)   364,277,890.12 ops
        }
    
    
    static void NativeDllCalls(bool useStatic, int nonParallelIterations, int parallelIterations = 0, int maxParallelism = 0)
    {
        if (useStatic) {
            Iterate(
                (msg, cntxt) => { 
                    ServiceContracts.ForNativeCall.SomeStaticCall(msg); 
                }
                , "test", null, nonParallelIterations,parallelIterations, maxParallelism );
        }
        else {
            var instance = new ServiceContracts.ForNativeCall();
            Iterate(
                (msg, cntxt) => {
                    cntxt.SomeCall(msg);
                }
                , "test", instance, nonParallelIterations, parallelIterations, maxParallelism);
        }
    }
    
    static void Iterate(Action action, T testMessage, C context, int nonParallelIterations, int parallelIterations=0, int maxParallelism= 0)
    {
        var start = DateTime.UtcNow;            
        if(nonParallelIterations == 0)
            nonParallelIterations = 1; // normalize values
    
        if(parallelIterations == 0)
            parallelIterations = 1; 
    
        if (parallelIterations > 1) {                    
            ParallelOptions options;
            if (maxParallelism == 0) // default max parallelism
                options = new ParallelOptions();
            else
                options = new ParallelOptions { MaxDegreeOfParallelism = maxParallelism };
    
            if (nonParallelIterations > 1) {
                Parallel.For(0, parallelIterations, options
                , (j) => {
                    for (int i = 0; i < nonParallelIterations; ++i) {
                        action(testMessage, context);
                    }
                });
            }
            else { // no nonParallel iterations
                Parallel.For(0, parallelIterations, options
                , (j) => {                        
                    action(testMessage, context);
                });
            }
        }
        else {
            for (int i = 0; i < nonParallelIterations; ++i) {
                action(testMessage, context);
            }
        }
    
        var end = DateTime.UtcNow;
    
        Console.WriteLine("\tSeconds: {0,8:0.00} |) {1,16:0,000.00} ops",
            (end - start).TotalSeconds, (Math.Max(parallelIterations, 1) * nonParallelIterations / (end - start).TotalSeconds));
    
    }
    
    }
    

提交回复
热议问题