Dimitri
Dimitri

Reputation: 2878

Several Tasks manipulating on same Object

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

Upvotes: 0

Views: 1634

Answers (3)

Mauro Cerutti
Mauro Cerutti

Reputation: 684

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 .

Upvotes: 1

Parv Sharma
Parv Sharma

Reputation: 12705

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

Upvotes: -1

Stephen Cleary
Stephen Cleary

Reputation: 457472

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

Upvotes: 2

Related Questions