Skip to content

Instantly share code, notes, and snippets.

@isaacabraham
Created October 2, 2013 11:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isaacabraham/6792050 to your computer and use it in GitHub Desktop.
Save isaacabraham/6792050 to your computer and use it in GitHub Desktop.
Sample of sequential vs parallel vs async code
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var urls = new[]
{
"http://www.tottenhamhotspur.com",
"http://cockneycoder.com",
"http://www.bbc.co.uk",
"http://www.bbc.co.uk/sport/0/football/",
"http://www.sky.com"
};
Console.WriteLine("Sequential");
Console.WriteLine();
Sequential(urls);
Console.WriteLine();
Console.WriteLine("Parallel");
Parallel(urls);
Console.WriteLine();
Console.WriteLine("Async");
Async(urls);
}
private static void Sequential(string[] urls)
{
var stopwatch = Stopwatch.StartNew();
int index = 0;
foreach (var url in urls)
{
Helpers.PrintStatus("Downloading", url, index);
new WebClient().DownloadString(new Uri(url));
Helpers.PrintStatus("Downloaded", url, index);
index++;
}
Console.WriteLine("Done in {0}ms.", stopwatch.ElapsedMilliseconds);
}
private static void Parallel(string[] urls)
{
var stopwatch = Stopwatch.StartNew();
System.Threading.Tasks.Parallel.ForEach(urls, (url,state,index) =>
{
Helpers.PrintStatus("Downloading", url, (int)index);
new WebClient().DownloadString(new Uri(url));
Helpers.PrintStatus("Downloaded", url, (int)index);
});
Console.WriteLine("Done in {0}ms.", stopwatch.ElapsedMilliseconds);
}
private static void Async(String[] urls)
{
var stopwatch = Stopwatch.StartNew();
var tasks = new Task[urls.Length];
System.Threading.Tasks.Parallel.ForEach(urls, (url, state, index) =>
{
Helpers.PrintStatus("Downloading", url, (int)index);
var wc = new WebClient();
wc.DownloadStringCompleted += (o, e) => Helpers.PrintStatus("Downloaded", url, (int)index);
tasks[(int)index] = wc.DownloadStringTaskAsync(new Uri(url));
});
Task.WaitAll(tasks);
Console.WriteLine("Done in {0}ms.", stopwatch.ElapsedMilliseconds);
}
}
public static class Helpers
{
public static ConsoleColor PickColor(int colorIndex)
{
var colors = new []
{
ConsoleColor.Cyan,
ConsoleColor.Yellow,
ConsoleColor.Red,
ConsoleColor.DarkCyan,
ConsoleColor.Green,
ConsoleColor.DarkYellow,
ConsoleColor.Gray,
};
var index = colorIndex;
while (index > colors.Length)
index -= colors.Length;
return colors[index];
}
private static Object latch = new object();
public static void PrintStatus(string message, string url, int index)
{
lock (latch)
{
Console.ForegroundColor = PickColor(index);
Console.WriteLine("{0} {1} on thread {2}", message, url, Thread.CurrentThread.ManagedThreadId);
Console.ForegroundColor = ConsoleColor.Gray;
}
}
}
}
@PrzemyslawLewandowski
Copy link

Why "Parallel.ForEach" for Async() method?
Isn't that better:

private static void MyAsync(IEnumerable<string> urls)
{
    var stopwatch = Stopwatch.StartNew();
    var tasks = urls.Select((u, i) =>
        {
            Helpers.PrintStatus("Downloading", u, i);
            var wc = new WebClient();
            wc.DownloadStringCompleted += (o, e) => Helpers.PrintStatus("Downloaded", u, i);
            return wc.DownloadStringTaskAsync(new Uri(u));
        }).ToArray();
    Task.WaitAll(tasks);
    Console.WriteLine("Done in {0}ms.", stopwatch.ElapsedMilliseconds);
}

@isaacabraham
Copy link
Author

Yes, you could do that. However, I wanted to keep the code as close to the other two versions as possible so as to best illustrate the difference in async code. If you chuck a select in there the reader might think that you can't use Parallel ForEach.

Also note that doing a plain Select() will still spawn each download off on the same thread e.g. Thread 1 - all Select does is a MoveNext() through the collection on the same thread - there's no multithreading there (although the results will come back on different threads, of course). You could do AsParallel().Select() to get around that, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment