I’m trying to wrap my head around the whole Parallel Programming concept, mostly focusing on Tasks, so I’ve been trying this scenario where, say, up to 9 Parallel Tasks would perform their work for a random period of time:
/// <remarks>
/// A big thank you to the awesome community of StackOverflow for
/// their advice and guidance with this sample project
/// http://stackoverflow.com/questions/5195486/
/// </remarks>
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
byte[] buffer = new byte[4];
random.GetBytes(buffer);
// Creates a random number of tasks (not less than 2 -- up to 9)
int iteration = new Random(BitConverter.ToInt32(buffer, 0)).Next(2,9);
Console.WriteLine("Creating " + iteration + " Parallel Tasks . . .");
Console.Write(Environment.NewLine);
Dictionary<int, string> items = new Dictionary<int, string>();
for (int i = 1; i < iteration + 1; i++) // cosmetic +1 to avoid "Task N° 0"
{
items.Add(i, "Task # " + i);
}
List<Task> tasks = new List<Task>();
// I guess we should use a Parallel.Foreach() here
foreach (var item in items)
{
// Creates a random interval to pause the thread at (up to 9 secs)
random.GetBytes(buffer);
int interval = new Random(BitConverter.ToInt32(buffer, 0)).Next(1000, 9000);
var temp = item;
var task = Task.Factory.StartNew(state =>
{
Console.WriteLine(String.Format(temp.Value + " will be completed in {0} miliseconds . . .", interval));
Thread.Sleep(interval);
return "The quick brown fox jumps over the lazy dog.";
}, temp.Value).ContinueWith(t => Console.WriteLine(String.Format("{0} returned: {1}", t.AsyncState, t.Result)));
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
But unfortunately they’re being handled sequentially instead of in parallel.
I’d be really glad if you guys could help me out here — maybe I should use a Parallel.ForEach instead of a regular one?
Again any advice would be really appreciated.
EDIT
Updated the code sample twice to reflect the contributions from the commenters.
Calling
Task.Resultblocks. Since you’re doing that inside yourforeachover items you end up creating one task and then waiting for it to finish before moving to the next item.try moving the call to
Task.Resultoutside thatforeachEDIT
As asked for in the comments. Here is a version that would print the result as each task finishes by using
ConinueWith. The task list can now be aList<Task>again as well. TheWaitAllcall is still needed at the end to make sure the method doesn’t return until each task is done, but each task will print it’s result as it finishes.