0

I created a simple test with big arrays, and I get a big difference between parallel for and normal for

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var rn = new Random(541);

            var tmStart = DateTime.Now;
            int[,] a = new int[2048, 2048];
            for (int i = 0; i < 2048; i++)
                for (int j = 0; j < 2048; j++)
                    a[i, j] = rn.Next();
            var tmEnd = DateTime.Now - tmStart;
            Console.WriteLine("Normal..: {0}",tmEnd.ToString());

            tmStart = DateTime.Now;
            a = new int[2048, 2048];
            Parallel.For(0, 2048, i =>
                {
                    for (int j = 0; j < 2048; j++)
                        a[i, j] = rn.Next();
                });
            tmEnd = DateTime.Now - tmStart;
            Console.WriteLine("Parallel: {0}", tmEnd.ToString());
        }
    }
}

The time for process:

Normal..: 00:00:00.1250071
Parallel: 00:00:00.3880222

Why is that difference so big?

I imagined that if you use several threads, it would be faster...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Alexandre
  • 1,985
  • 5
  • 30
  • 55
  • 1
    try it with much bigger arrays. There is overhead to create threads, so the parallel will likely be faster once you get to a sufficient workload – jle Jul 08 '14 at 13:53
  • As well as being slower, you are breaking the threading rules. You need to serialize access to `rn`. – David Heffernan Jul 08 '14 at 13:53
  • This question has been asked before... – Dennis_E Jul 08 '14 at 13:54
  • How many CPUs/Cores to you have? – Allan S. Hansen Jul 08 '14 at 13:54
  • 4
    There's just so many things wrong with this benchmark, there really isn't even much of a point trying to salvage it... – Luaan Jul 08 '14 at 13:55
  • @Dennis_E: I'm sure it has. Find such a question and I'll happily click close as duplicate. ;-) – Chris Jul 08 '14 at 13:55
  • 1
    At least use `System.Diagnostics.Stopwatch` for your timing and make sure you do not run with the debugger attached and in release mode, also note that x86 and x64 will produce different timings to each other. Do multiple runs with an un-timed run to start with to warm up the code, then average the time across the runs. Also, they are not large arrays. – Adam Houldsworth Jul 08 '14 at 13:56
  • Uhh.. Using `DateTime.Now` for measuring time spent is a no no. Use Stopwatch, it's there for a reason. – Patrick Jul 08 '14 at 13:56
  • 1
    @Alexandre Parallelising code isn't the silver bullet people think it is. The simplest question to ask is: can many hands make light work? If you can do a task faster on your own, then leave it alone. If a task can benefit from lots of people working on it plus the overhead of managing those people, then do that. The deciding factor in all of this is *domain knowledge*. You will know when your code can benefit from it, such as doing 3 database calls at once on expensive tables, regardless of how exactly expensive they are. Case by case with this. – Adam Houldsworth Jul 08 '14 at 14:05

2 Answers2

2

When you parallelize tasks you have some "context switch" time spent from the SO to manage various tasks. If the single task isn't doing something computationally interesting you will not perceive any benefit from multithreading. You should choose some other example in which each task is eating some CPU cycles ( even a loop would do as an exercise purpose ).

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
1

There are a few things wrong with your benchmark:

  1. Your tasks are so small that the threading overhead is significant.
  2. You break the threading rules with the instance of Random. Who knows what impact this has?
  3. Your timing is, well, crude.

Here's a better benchmark that shows the parallel version of the code being faster:

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        const int N = 1024;

        static void Main(string[] args)
        {
            int[,] a = new int[N, N];

            var stopwatch = Stopwatch.StartNew();
            for (int i = 0; i < N; i++)
                for (int k = 0; k < N; k++)
                    for (int j = 0; j < N; j++)
                        a[i, j] = i+j;
            Console.WriteLine("Normal..: {0}", stopwatch.ElapsedMilliseconds);

            stopwatch = Stopwatch.StartNew();
            Parallel.For(0, N, i =>
            {
                for (int k = 0; k < N; k++)
                    for (int j = 0; j < N; j++)
                        a[i, j] = i+j;
            });
            Console.WriteLine("Parallel: {0}", stopwatch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

And here's one which uses random number generators:

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        const int N = 512;

        static void Main(string[] args)
        {
            int[,] a = new int[N, N];

            var stopwatch = Stopwatch.StartNew();
            var rng = new Random();
            for (int i = 0; i < N; i++)
                for (int k = 0; k < N; k++)
                    for (int j = 0; j < N; j++)
                        a[i, j] = rng.Next();
            Console.WriteLine("Normal..: {0}", stopwatch.ElapsedMilliseconds);

            stopwatch = Stopwatch.StartNew();
            Parallel.For(0, N, i =>
            {
                var rngpar = new Random();
                for (int k = 0; k < N; k++)
                    for (int j = 0; j < N; j++)
                        a[i, j] = rngpar.Next();
            });
            Console.WriteLine("Parallel: {0}", stopwatch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490