teenup
teenup

Reputation: 7667

Why can't I reach 100% CPU utilization with my parallel tasks code?

private static async Task<int> SumParallel()
        {
            var intList = Enumerable.Range(1, 1000_000_000);
            int count = intList.Count();
            int total = 0;
            for(int i = 1; i < 5; i++)
            {
                int skip = ((i - 1) * count) / 4;
                int take = count / 4;
                Interlocked.Add(ref total,
                    await GetSum(intList, skip, take));
            }
            return total;
        }

private static async Task<int> GetSum(IEnumerable<int> list, int skip, int take)
        {
            return await Task.Run(() =>
             {
                 int temp = 0;
                 foreach(int n in list.Skip(skip).Take(take))
                 {
                     if (n % 2 == 0)
                         temp -= n;
                     else
                         temp += n;
                 }
                 return temp;
             });
        }

I am trying to perform compute intensive task, just to practice the task parallel library. So, I wrote this code. If I try to compute the same sum using Parallel Linq, I can see the CPU utilization going to 100% as follows:

int sum = Enumerable.Range(1, 1000_000_000)
                .AsParallel()
                .Select(i => i % 2 == 0 ? -i : i).Sum();

Manual parallel tasks code = 10 seconds time, cpu = 25% only

Parallel Linq code = 18 seconds time, cpu = 100% (And still takes 18 seconds)

Linq code without parallel: 14 seconds, cpu = 25% only

Why is it so? When I am also starting 4 threads in parallel, why my cpu utilization doesn't go to 100%? It is just 25% like there is in unparallel code (with just one thread). Am I really running 4 threads in parallel or not?

My laptop is Core i3 - 2 cores = 4 logical processors

Upvotes: 1

Views: 285

Answers (1)

Theodor Zoulias
Theodor Zoulias

Reputation: 43525

The SumParallel is not doing parallel job, because it creates and awaits each task sequentially:

for(int i = 1; i < 5; i++) {
    //...
    await GetSum(intList, skip, take)

To make it parallel you must start all five tasks, and then await all of them to complete with await Task.WhenAll(tasks);.

As for the Parallel Linq being slower than the standard Linq, it is because your workload is too granular. As a result the overhead of parallelism negates any benefits of the parallel execution. In other words it is more work to distribute the items to the threads and collect the results back, than the actual calculation (n % 2). To make the most out of parallelism, your workload must be chunky.

Upvotes: 2

Related Questions