代码之家  ›  专栏  ›  技术社区  ›  Elisabeth

我应该一直使用parallel.foreach吗?因为更多的线程必须加速所有操作?

  •  38
  • Elisabeth  · 技术社区  · 15 年前

    对于每个正常的foreach使用parallel.foreach循环是否有意义?

    我应该何时开始使用parallel.foreach,只迭代1000000个项目?

    8 回复  |  直到 9 年前
        1
  •  66
  •   Jon Skeet    15 年前

    • Parallel.ForEach

        2
  •  19
  •   user2441511    9 年前

    Input = Enumerable.Range(1, Count).ToArray();
    Result = new double[Count];
    
    Parallel.ForEach(Input, (value, loopState, index) => { Result[index] = value*Math.PI; });
    

    Parallel.ForEach(Partitioner.Create(0, Input.Length), range => {
       for (var index = range.Item1; index < range.Item2; index++) {
          Result[index] = Input[index]*Math.PI;
       }
    });
    

        3
  •  13
  •   Community Mohan Dere    9 年前

    Parallel.ForEach break

    Does Parallel.ForEach limits the number of active threads? Does Parallel.For use one Task per iteration?

    var tasks = new List<Task>(actions.Length); 
    foreach(var action in actions) 
    { 
        tasks.Add(Task.Factory.StartNew(action)); 
    } 
    Task.WaitAll(tasks.ToArray());
    

    Microsoft documentation

    namespace ParallelTests 
    { 
        class Program 
        { 
            private static int Fibonacci(int x) 
            { 
                if (x <= 1) 
                { 
                    return 1; 
                } 
                return Fibonacci(x - 1) + Fibonacci(x - 2); 
            } 
    
            private static void DummyWork() 
            { 
                var result = Fibonacci(10); 
                // inspect the result so it is no optimised away. 
                // We know that the exception is never thrown. The compiler does not. 
                if (result > 300) 
                { 
                    throw new Exception("failed to to it"); 
                } 
            } 
    
            private const int TotalWorkItems = 2000000; 
    
            private static void SerialWork(int outerWorkItems) 
            { 
                int innerLoopLimit = TotalWorkItems / outerWorkItems; 
                for (int index1 = 0; index1 < outerWorkItems; index1++) 
                { 
                    InnerLoop(innerLoopLimit); 
                } 
            } 
    
            private static void InnerLoop(int innerLoopLimit) 
            { 
                for (int index2 = 0; index2 < innerLoopLimit; index2++) 
                { 
                    DummyWork(); 
                } 
            } 
    
            private static void ParallelWork(int outerWorkItems) 
            { 
                int innerLoopLimit = TotalWorkItems / outerWorkItems; 
                var outerRange = Enumerable.Range(0, outerWorkItems); 
                Parallel.ForEach(outerRange, index1 => 
                { 
                    InnerLoop(innerLoopLimit); 
                }); 
            } 
    
            private static void TimeOperation(string desc, Action operation) 
            { 
                Stopwatch timer = new Stopwatch(); 
                timer.Start(); 
                operation(); 
                timer.Stop(); 
    
                string message = string.Format("{0} took {1:mm}:{1:ss}.{1:ff}", desc, timer.Elapsed); 
                Console.WriteLine(message); 
            } 
    
            static void Main(string[] args) 
            { 
                TimeOperation("serial work: 1", () => Program.SerialWork(1)); 
                TimeOperation("serial work: 2", () => Program.SerialWork(2)); 
                TimeOperation("serial work: 3", () => Program.SerialWork(3)); 
                TimeOperation("serial work: 4", () => Program.SerialWork(4)); 
                TimeOperation("serial work: 8", () => Program.SerialWork(8)); 
                TimeOperation("serial work: 16", () => Program.SerialWork(16)); 
                TimeOperation("serial work: 32", () => Program.SerialWork(32)); 
                TimeOperation("serial work: 1k", () => Program.SerialWork(1000)); 
                TimeOperation("serial work: 10k", () => Program.SerialWork(10000)); 
                TimeOperation("serial work: 100k", () => Program.SerialWork(100000)); 
    
                TimeOperation("parallel work: 1", () => Program.ParallelWork(1)); 
                TimeOperation("parallel work: 2", () => Program.ParallelWork(2)); 
                TimeOperation("parallel work: 3", () => Program.ParallelWork(3)); 
                TimeOperation("parallel work: 4", () => Program.ParallelWork(4)); 
                TimeOperation("parallel work: 8", () => Program.ParallelWork(8)); 
                TimeOperation("parallel work: 16", () => Program.ParallelWork(16)); 
                TimeOperation("parallel work: 32", () => Program.ParallelWork(32)); 
                TimeOperation("parallel work: 64", () => Program.ParallelWork(64)); 
                TimeOperation("parallel work: 1k", () => Program.ParallelWork(1000)); 
                TimeOperation("parallel work: 10k", () => Program.ParallelWork(10000)); 
                TimeOperation("parallel work: 100k", () => Program.ParallelWork(100000)); 
    
                Console.WriteLine("done"); 
                Console.ReadLine(); 
            } 
        } 
    } 
    

    serial work: 1 took 00:02.31 
    serial work: 2 took 00:02.27 
    serial work: 3 took 00:02.28 
    serial work: 4 took 00:02.28 
    serial work: 8 took 00:02.28 
    serial work: 16 took 00:02.27 
    serial work: 32 took 00:02.27 
    serial work: 1k took 00:02.27 
    serial work: 10k took 00:02.28 
    serial work: 100k took 00:02.28 
    
    parallel work: 1 took 00:02.33 
    parallel work: 2 took 00:01.14 
    parallel work: 3 took 00:00.96 
    parallel work: 4 took 00:00.78 
    parallel work: 8 took 00:00.84 
    parallel work: 16 took 00:00.86 
    parallel work: 32 took 00:00.82 
    parallel work: 64 took 00:00.80 
    parallel work: 1k took 00:00.77 
    parallel work: 10k took 00:00.78 
    parallel work: 100k took 00:00.77 
    done
    

        4
  •  9
  •   Gabe Timothy Khouri    13 年前

    Parallel.ForEach

    for

    2 outer iterations, 100000000 inner iterations:
    for loop: 00:00:00.1460441
    ForEach : 00:00:00.0842240
    

    100000000 outer iterations, 2 inner iterations:
    for loop: 00:00:00.0866330
    ForEach : 00:00:02.1303315
    

        5
  •  1
  •   Darin Dimitrov    15 年前

        6
  •  1
  •   Jon Hanna    15 年前

        7
  •  0
  •   tvanfosson    15 年前

        8
  •  0
  •   AaronLS    11 年前

    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<string, object>(
                (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<T, C>(Action<T, C> 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));
    
    }
    
    }