Geeks With Blogs

News This is the *old* blog. The new one is at blog.sixeyed.com
Elton Stoneman
This is the *old* blog. The new one is at blog.sixeyed.com

[Source: http://geekswithblogs.net/EltonStoneman]

Using Parallel Extensions you can reduce loop execution time by 95%. Which, if you're evaluating .NET 4.0 and VS 2010, should be a cinching argument*.

The Parallel Extensions library includes an abundance of features for fine-grained control over concurrent operations, and it also provides the very simple Parallel.ForEach construct, which takes an IEnumerable<> collection and an Action to run over each item, so:

    foreach (var item in GetItems(collectionSize))

    {

        ServiceCall(item);

    }

- becomes:

    Parallel.ForEach(GetItems(collectionSize), x => ServiceCall(x));

The ForEach method partitions the collection and intelligently distributes work amongst the available processors and cores. The workload on the cores is actively monitored while work is being apportioned, so the distribution should be evenly spread whether the actions themselves are an even load or not.

In a simple test rig (available on github here: TPL Sample), I call a stub WCF service in a repeated loop – one version uses a sequential foreach, the other uses Parallel.ForEach. On a dual-core machine, the parallel version completes on average in less than 20% of the time of the sequential version:

But it gets better. Parallel.ForEach is thread-intensive and intended for heavy computional work; for blocking I/O operations like service calls, use of the Task class is preferred. This lets you fire off asynchoronous tasks and wait for the responses without blocking threads:

    var collection = GetItems(collectionSize).ToArray();

    var tasks = new Task[collectionSize];

    for (int i=0; i<collectionSize; i++)

    {

        var item = collection[i];

        tasks[i] = Task.Factory.StartNew(() => ServiceCall(item));

    }

    Task.WaitAll(tasks);

So with this approach you can farm out background tasks in a Web service without the risk of starving the ThreadPool so ASP.NET stops processing new requests.

Note that you must use an array of tasks, and you must pull the target item out of the collection before you add it as an action parameter to the task array – don't try and use List<Task> or () => ServiceCall(collection[i]), you'll either get an index out of range error, or the tasks will all fire against the first item.

For small collections (calling the service 200 times), the Task method runs in less than 15% of the time for the sequential version:

And for larger collections (3,000 service calls), the improvement is even more impressive - Parallel.ForEach running in 10% of the sequential version's time, and the Task version in 5%:

Improvements aren't limited to multi-core boxes either, you'll still see significant – if less impressive – reduction in processing times on single-core, single-CPU machines.

The usual caveat for performance improvements apply here – you need to test before and after in your own scenarios – and with the parallel extensions, you also need to take your server load into account. Run your tests with no load to get an idea of the maximum improvement available, and run with typical load to see what the real improvement is likely to be.

Microsoft has an excellent introduction to the parallel extensions here: Patterns of Parallel Programming (CSharp) (pdf), which covers the parallel extensions in greater detail.

 

* - the Reactive Extensions on DevLabs contain a port of the parallel extensions in the System.Threading dll which can be used with .NET 3.5 SP1, but it's unsupported and doesn't have the same level of performance as the native TPL in .NET 4.0. If you're upgrade argument isn't convincing enough and you're limited to 3.5 SP1, the ported version still makes for a big improvement over sequential processing.

Posted on Monday, August 9, 2010 8:00 PM .NET 4.0 | Back to top


Comments on this post: One Good Reason to Upgrade to .NET 4.0

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
The ForEach method partitions the collection and intelligently distributes work amongst the available processors and cores. The workload on the cores is actively monitored while work is being apportioned, so the distribution should be evenly spread whether the actions themselves are an even load or not.
Left by Local Jobs UK on Aug 12, 2010 3:13 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
I don't get it but will tell my people upgrade anyways ;)
Left by Deko on Aug 13, 2010 3:02 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
I remember the upgrade to 3.0 turned out to be a complete nightmare for me. I've since subscribed to the "if it ain't broken, don't fix it" approach.
Left by Wordpress Membership Plugins on Aug 13, 2010 5:37 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
WOW! Your test results say it all. That PDF is involved but great reading! One question on your last test you said without starving your threadpool - Do you mean if you pooled the locks would have kept the connections open?
Left by Kenl_mcse on Aug 16, 2010 3:21 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
Nice post.I never come across such a lovely post which is very well written, to the point.Thanks a lot for sharing. Keep blogging.
Left by Oil Filled Radiators on Sep 18, 2010 3:21 AM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
This sure helps me understand the need to upgrade to .NET 4.0.
Left by flag pole on Sep 29, 2010 4:03 PM

# What is the benchmark against threads?
Requesting Gravatar...
I am interested in seeing the same 300 calls using threads and thread.Join vs Tasks.
Left by Peter on Oct 12, 2010 3:00 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
This seems a little too complicated for me, but thanks all the same, honestly.
Left by HGH on Oct 17, 2010 5:13 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
The only reason I know if is increased productivity, its one Good Reason to Upgrade to .NET 4.0.
Left by colocation utah on Jan 24, 2011 6:21 AM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
Entity Framework is a lot better in .NET 4. It supports directly accessing foreign keys, and works as expected with Linq. It also provides the very simple Parallel forEach construct, which takes an IEnumerable collection and an Action to run over each item.
Left by article distribution on Mar 25, 2011 2:13 AM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
This is actually a strong reasonn to upgrade.
Left by 0x00000050 on Jun 22, 2011 4:48 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
Thanks for this details on parallel extension really appreciate for sharing it, i will be really back to read more such post.
Left by Weight Loss Surgeon on Dec 26, 2011 9:35 AM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
Fantastic concepts on this website. Its rare nowadays to discover web sites with information you are seeking. real estate toronto
Left by florcajes on Dec 27, 2011 7:08 AM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
I would appreciate you that you pick up an important topic to write a thoroughly informative post on. I hope that you never stop and keep posting such valuable content learning english | asia teaching
Left by maicastro on Dec 28, 2011 8:33 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
very helpfull, nace share, thanks a lot
Left by cara mudah membuat website on Aug 03, 2012 1:19 PM

# re: One Good Reason to Upgrade to .NET 4.0
Requesting Gravatar...
The only reason I know if is increased productivity, its one Good Reason to Upgrade to .NET 4.0. Independent Mumbai escorts Tara
Left by Tara on Jun 04, 2014 1:45 PM

Your comment:
 (will show your gravatar)


Copyright © Elton Stoneman | Powered by: GeeksWithBlogs.net