Note that there are some explanatory texts on larger screens.

plurals
  1. POC# Asynchronous Options for Processing a List
    text
    copied!<p>I am trying to better understand the Async and the Parallel options I have in C#. In the snippets below, I have included the 5 approaches I come across most. But I am not sure which to choose - or better yet, what criteria to consider when choosing: </p> <p><strong>Method 1: Task</strong></p> <p>(see <a href="http://msdn.microsoft.com/en-us/library/dd321439.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/dd321439.aspx</a>)</p> <blockquote> <p><em>Calling StartNew is functionally equivalent to creating a Task using one of its constructors and then calling Start to schedule it for execution. However, unless creation and scheduling must be separated, StartNew is the recommended approach for both simplicity and performance.</em></p> <p><em>TaskFactory's StartNew method should be the preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation and scheduling must be separated, the constructors may be used, and the task's Start method may then be used to schedule the task for execution at a later time.</em></p> </blockquote> <pre><code>// using System.Threading.Tasks.Task.Factory void Do_1() { var _List = GetList(); _List.ForEach(i =&gt; Task.Factory.StartNew(_ =&gt; { DoSomething(i); })); } </code></pre> <p><strong>Method 2: QueueUserWorkItem</strong></p> <p>(see <a href="http://msdn.microsoft.com/en-us/library/system.threading.threadpool.getmaxthreads.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/system.threading.threadpool.getmaxthreads.aspx</a>)</p> <blockquote> <p><em>You can queue as many thread pool requests as system memory allows. If there are more requests than thread pool threads, the additional requests remain queued until thread pool threads become available.</em></p> <p><em>You can place data required by the queued method in the instance fields of the class in which the method is defined, or you can use the QueueUserWorkItem(WaitCallback, Object) overload that accepts an object containing the necessary data.</em></p> </blockquote> <pre><code>// using System.Threading.ThreadPool void Do_2() { var _List = GetList(); var _Action = new WaitCallback((o) =&gt; { DoSomething(o); }); _List.ForEach(x =&gt; ThreadPool.QueueUserWorkItem(_Action)); } </code></pre> <p><strong>Method 3: Parallel.Foreach</strong></p> <p>(see: <a href="http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx</a>)</p> <blockquote> <p><em>The Parallel class provides library-based data parallel replacements for common operations such as for loops, for each loops, and execution of a set of statements.</em></p> <p><em>The body delegate is invoked once for each element in the source enumerable. It is provided with the current element as a parameter.</em></p> </blockquote> <pre><code>// using System.Threading.Tasks.Parallel void Do_3() { var _List = GetList(); var _Action = new Action&lt;object&gt;((o) =&gt; { DoSomething(o); }); Parallel.ForEach(_List, _Action); } </code></pre> <p><strong>Method 4: IAsync.BeginInvoke</strong></p> <p>(see: <a href="http://msdn.microsoft.com/en-us/library/cc190824.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/cc190824.aspx</a>)</p> <blockquote> <p><em>BeginInvoke is asynchronous; therefore, control returns immediately to the calling object after it is called.</em></p> </blockquote> <pre><code>// using IAsync.BeginInvoke() void Do_4() { var _List = GetList(); var _Action = new Action&lt;object&gt;((o) =&gt; { DoSomething(o); }); _List.ForEach(x =&gt; _Action.BeginInvoke(x, null, null)); } </code></pre> <p><strong>Method 5: BackgroundWorker</strong></p> <p>(see: <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx</a>)</p> <blockquote> <p><em>To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.</em></p> </blockquote> <pre><code>// using System.ComponentModel.BackgroundWorker void Do_5() { var _List = GetList(); using (BackgroundWorker _Worker = new BackgroundWorker()) { _Worker.DoWork += (s, arg) =&gt; { arg.Result = arg.Argument; DoSomething(arg.Argument); }; _Worker.RunWorkerCompleted += (s, arg) =&gt; { _List.Remove(arg.Result); if (_List.Any()) _Worker.RunWorkerAsync(_List[0]); }; if (_List.Any()) _Worker.RunWorkerAsync(_List[0]); } } </code></pre> <p>I suppose the obvious critieria would be:</p> <ol> <li>Is any better than the other for performance?</li> <li>Is any better than the other for error handling?</li> <li>Is any better than the other for monitoring/feedback?</li> </ol> <p>But, how do <strong>you</strong> choose? Thanks in advance for your insights.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload