【问题标题】:Why my parallel for loop is much slower than for?为什么我的并行 for 循环比 for 慢得多?
【发布时间】:2021-07-31 15:17:33
【问题描述】:

我尝试将我的 for 循环更改为并行循环,但它的速度慢得多,而不是在一分钟内完成循环,而是在 30 分钟内完成。循环的作用是从一个数字开始检查它是​​奇数还是偶数。如果是奇数,则乘以 3 并加 1。如果是偶数,则将其除以 2。继续重复直到数字达到 4,并且有一个循环,每次重复一百万次,数字高一。我提到的最后一个循环是我尝试更改为并行循环的循环。下面是普通 for 循环的代码:

        static void Main(string[] args)
        {
            
            BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
            BigInteger currentValue;
            Console.WriteLine(currenthighest);
            Console.ReadKey();
            for (int i = 1; i > -1; i++)
            {
               
                for (int z = 0; z != 1000000; z++)
                 {
                     currentValue = currenthighest;
                     while (currentValue != 4)
                     {
                         if (currentValue % 2 == 0)
                         {
                             currentValue = currentValue / 2;
                         }
                         else
                         {
                             currentValue = (currentValue * 3) + 1;
                         }
                     }
                     currenthighest++;
                 }    
                Console.WriteLine(" {0} times done", i * 1000000);
            } 
        }

这里是并行代码:

        static void Main(string[] args)
        {
            
            BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
            BigInteger currentValue;
            Console.WriteLine(currenthighest);
            Console.ReadKey();
            for (int i = 1; i > -1; i++)
            {
               
                Parallel.For(0, 1000000,z=>
                 {
                     currentValue = currenthighest;
                     while (currentValue != 4)
                     {
                         if (currentValue % 2 == 0)
                         {
                             currentValue = currentValue / 2;
                         }
                         else
                         {
                             currentValue = (currentValue * 3) + 1;
                         }
                     }
                     currenthighest++;
                 });   
                Console.WriteLine(" {0} times done", i * 1000000);
            } 
        }

有人可以帮我让它比普通的 for 循环更快,或者在这种情况下使用并行是愚蠢的,我应该只使用普通的 for 循环吗?如果我也将感谢任何帮助使正常的 for 循环更快。

【问题讨论】:

  • 除了速度较慢之外,并行版本也不正确,因为currenthighest++操作is not thread-safe
  • 我的假设是线程中的工作量小于上下文切换的成本。
  • 相关:Multiplying arrays element-wise has unexpected performance in C#。这个问题表明,当Parallel.For因为工作负载太细化而达不到要求时,您可以通过切换到Parallel.ForEach(Partitioner.Create(0, 1000000)来对其进行分块。另请注意,Parallel.For/Parallel.ForEach 方法在未配置 MaxDegreeOfParallelism 的情况下使用时,会使ThreadPoolwhich is bad 饱和。

标签: c# loops for-loop parallel-processing console


【解决方案1】:

正如 Theodor Zoulias 指出的那样,性能不足的原因可能是因为它不是线程安全的。这可能导致数字取任意值,并可能导致执行完全不同的计算。

要解决此问题,您需要使每个并行循环独立。据我所知,这在您的示例中很容易做到,因为您只需要确保所有修改的值都是本地的:

 static void Main(string[] args)
 {
        
        BigInteger startvalue =new BigInteger(Math.Pow(2,68));
        Console.WriteLine(startvalue );
        Console.ReadKey();
        for (int i = 1; i > -1; i++)
        {
            Parallel.For(0, 1000000,z=>
             {
                 var currentValue = startvalue + z;
                 while (currentValue != 4)
                 {
                     if (currentValue % 2 == 0)
                     {
                         currentValue = currentValue / 2;
                     }
                     else
                     {
                         currentValue = (currentValue * 3) + 1;
                     }
                 }
             });   
            Console.WriteLine(" {0} times done", i * 1000000);
       }
    }

另一种可能性是并行循环内的工作平均非常小,导致线程开销很大。还有工作平衡的问题,Parallel.For 将在“块”中工作以减少这种线程开销,并尝试调整这些块的大小。如果工作量变化很大,这种适应可能会导致效率低下。

【讨论】:

  • 谢谢,乔纳斯。现在每百万只需要大约 20 秒。正常的 for 循环需要一分钟
猜你喜欢
  • 2019-09-29
  • 2017-01-29
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 2017-11-09
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多