Elton Stoneman

  Home  |   Contact  |   Syndication    |   Login
  123 Posts | 0 Stories | 3755 Comments | 0 Trackbacks

News

Archives

Post Categories

[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 09, 2010 8:00 PM

Feedback

# re: One Good Reason to Upgrade to .NET 4.0 8/12/2010 3:13 PM Local Jobs UK
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.

# re: One Good Reason to Upgrade to .NET 4.0 8/13/2010 3:02 PM Deko
I don't get it but will tell my people upgrade anyways ;)

# re: One Good Reason to Upgrade to .NET 4.0 8/13/2010 5:37 PM Wordpress Membership Plugins
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.

# re: One Good Reason to Upgrade to .NET 4.0 8/16/2010 3:21 PM Kenl_mcse
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?

# re: One Good Reason to Upgrade to .NET 4.0 9/18/2010 3:21 AM Oil Filled Radiators
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.

# re: One Good Reason to Upgrade to .NET 4.0 9/29/2010 4:03 PM flag pole
This sure helps me understand the need to upgrade to .NET 4.0.

# What is the benchmark against threads? 10/12/2010 3:00 PM Peter
I am interested in seeing the same 300 calls using threads and thread.Join vs Tasks.

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

# re: One Good Reason to Upgrade to .NET 4.0 1/24/2011 6:21 AM colocation utah
The only reason I know if is increased productivity, its one Good Reason to Upgrade to .NET 4.0.

# re: One Good Reason to Upgrade to .NET 4.0 3/25/2011 2:13 AM article distribution
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.

# re: One Good Reason to Upgrade to .NET 4.0 6/22/2011 4:48 PM 0x00000050
This is actually a strong reasonn to upgrade.

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

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

# re: One Good Reason to Upgrade to .NET 4.0 12/28/2011 8:33 PM maicastro
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

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: