yosefouad
yosefouad

Reputation: 3

Why my parallel for loop is much slower than for?

I tried changing my for loop with a parallel one but it's soo much slower instead of finishing the loop in a minute it finishes in 30 minutes. What the loop does is start with a number check if it's odd and if it's even. If it's odd it multiples by 3 and adds 1. If it's even it divides it by 2. Keep repeating that until the number reaches 4, and there is a loop around that repeats that a million times each time with a number higher by one. The last loop I mentioned is the loop I try to change to a parallel one. Here is the code for the normal for loop:

        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);
            } 
        }

And here is the code for the parallel one:

        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);
            } 
        }

Can someone help me make it faster than a normal for loop or is using parallel in this situation stupid and I should just use normal for loop? If I will also appreciate any help to make normal for loop faster.

Upvotes: 0

Views: 1145

Answers (1)

JonasH
JonasH

Reputation: 36391

The reason for the performance deficit if as Theodor Zoulias points out probably due to it not being thread-safe. This can cause numbers to take arbitrary values and may cause totally different calculations to be performed.

To fix this you need to make each parallel loop independent. As far as I can tell this would be rather easy to do in your example since you only need to ensure that all modified values are local:

 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);
       }
    }

Another possibility is that the work inside the parallel loop is on average quite small, causing the threading overhead to be significant. There is also the issue of work-balancing, Parallel.For will do work in 'chunks' to reduce this threading overhead, and try to adapt the size of these chunks. If the amount of work is highly variable this adaptation will probably result in inefficiencies.

Upvotes: 2

Related Questions