0

So was I just doing some experiments with Task class in c# and the following thing happens.

Here is the method I call

static async Task<List<int>> GenerateList(long size, int numOfTasks)
{
    var nums = new List<int>();

    Task[] tasks = new Task[numOfTasks];

    for (int i = 0; i < numOfTasks; i++)
    {
        tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random>
    }

    for (long i = 0; i < size; i += numOfTasks)
    {
        await Task.WhenAll(tasks);
    }

    return nums;
}

I call this method like this

var nums = GenerateList(100000000, 10).Result;

before I used Tasks generation took like 4-5 seconds. after I implemented this method like this if I pass 10-20 number of tasks the time of generation is lowered to 1,8-2,2 seconds but the thing it the List which is return by the method has numOfTask number of Elements in it so in this case List of ten numbers is returned. May be I'm writing something wrong. What can be the problem here. Or may be there is another solution to It. All I want it many task to add numbers in the same list so the generation time would be at least twice faster. Thanks In advance

Dimitri
  • 2,798
  • 7
  • 39
  • 59

3 Answers3

2

WhenAll does not run the tasks; it just (asynchronously) waits for them to complete. Your code is only creating 10 tasks, so that's why you're only getting 10 numbers. Also, as @Mauro pointed out, List<T>.Add is not threadsafe.

If you want to do parallel computation, then use Parallel or Parallel LINQ, not async:

static List<int> GenerateList(int size, int numOfTasks)
{
    return Enumerable.Range(0, size)
        .AsParallel()
        .WithDegreeOfParallelism(numOfTasks)
        .Select(_ => Rand.Value.Next())
        .ToList();
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

As explained by Stephen, you are only creating 10 tasks.

Also, I believe the Add operation on the generic list is not thread safe. You should use a locking mechanism or, if you are targeting framework 4 or newer, use thread-safe collections .

Mauro Cerutti
  • 684
  • 4
  • 9
-1

you are adding to the list in the following loop which runs for only 10 times

for (int i = 0; i < numOfTasks; i++)
    {
        tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random>
    }

you can instead do

for (int i = 0; i < numOfTasks; i++)
    {
        tasks[i] = new Task(() => nums.Add(Rand.Nex()));
    }
svick
  • 236,525
  • 50
  • 385
  • 514
Parv Sharma
  • 12,581
  • 4
  • 48
  • 80
  • What I want to do is to have suppose 10 task that will add numbers to list and run them in the seconds task – Dimitri Jan 23 '14 at 09:00
  • can I run task array without running every of them distinctively in loop ? – Dimitri Jan 23 '14 at 09:22
  • This won't work, it creates unstarted `Task`s and then never starts them. And even if you do that, you can only start each `Task` once. – svick Jan 23 '14 at 14:49
  • @svick - i know that.. i was just telling the questioner how to make tasks without starting them – Parv Sharma Jan 24 '14 at 06:35
  • 1. So, why didn't you say so? The text of your answer doesn't say that. 2. How does that answer the question ? – svick Jan 24 '14 at 11:07
  • i pointed out a problem in the code. Text of my answer exactly says this. anyways thats for the help.. ill updated my ans soon – Parv Sharma Jan 24 '14 at 11:10