Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Your code blocks a ThreadPool thread for 5 seconds. If you execute this code for a large number of events you may exhaust all threadpool threads and effectively block your application until all the Sleep statements finish.</p> <p>Both the code samples execute using the default thread scheduler. The difference is that the second sample uses the TaskCreationOptions.LongRunning which instructs the scheduler to create new threads rather than wait for a pool thread. This may overcome the initial problem, it's still not the right solution, as you are still wasting threads and may leave no thread available for other tasks. </p> <p>A correct implementation is to use a TaskSource that will be signalled when a timer expires. This way you are not blocking any threads.</p> <p>C# 5 already supports this with the <a href="http://msdn.microsoft.com/en-us/library/hh160377%28v=vs.110%29" rel="nofollow">Task.Delay</a> method. You can use this in .NET 4.0 if you use the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=29576" rel="nofollow">async targeting pack</a> for Visual Studio 2012 or the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=9983" rel="nofollow">Async v3 CTP</a> for 2010</p> <p>You can also find a similar method in the ParallelExtensionExtras library. The <a href="http://blogs.msdn.com/b/pfxteam/archive/2010/04/04/9990342.aspx" rel="nofollow">TaskFactory.StartNewDelayed</a> extension method works in almost the same way. The sample code <a href="http://blogs.msdn.com/b/pfxteam/archive/2009/06/03/9691796.aspx" rel="nofollow">from Stephen Toub's article</a> provides a simplified version:</p> <pre><code>public static Task StartNewDelayed(int millisecondsDelay, Action action) { // Validate arguments if (millisecondsDelay &lt; 0) throw new ArgumentOutOfRangeException("millisecondsDelay"); if (action == null) throw new ArgumentNullException("action"); // Create a trigger used to start the task var tcs = new TaskCompletionSource&lt;object&gt;(); // Start a timer that will trigger it var timer = new Timer( _ =&gt; tcs.SetResult(null), null, millisecondsDelay, Timeout.Infinite); // Create and return a task that will be scheduled when the trigger fires. return tcs.Task.ContinueWith(_ =&gt; { timer.Dispose(); action(); }); } </code></pre> <p>Using the version from the ParallelExtensionsExtras you can rewrite your code as follows:</p> <pre><code>Task.Factory.StartNewDelayed(5000).ContinueWith(_ =&gt; { lblStatus.Text = "Done"; }, TaskScheduler.FromCurrentSynchronizationContext()); </code></pre> <p><strong>EDIT:</strong></p> <p>It seems the actual code does not have a Thread.Sleep after all. It performs some heavy DB related operations. The effect is the same though. Starting a new task after each BindingSource event can lead to so many running tasks that the threadpool gets exhausted.</p> <p>One solution is again to use the TaskCreationOptions.LongRunning flag with the <a href="http://msdn.microsoft.com/en-us/library/dd321263" rel="nofollow">TaskFactory.StartNew(Action,TaskCreationOptions)</a> override to instruct the scheduler to create more threads.</p> <p>An even better solution is to execute the database operations asynchronously, using the BeginExecuteXXX,EndExecuteXXX methods combined with <a href="http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.fromasync" rel="nofollow">TaskFactory.FromAsync</a> to convert the asynchronous calls to tasks. This way the database operations will not block any threads at all.</p> <p>You could write something like this:</p> <pre><code>Task&lt;SqlDataReader&gt; task = Task&lt;SqlDataReader&gt;.Factory.FromAsync( cmd.BeginExecuteReader(CommandBehavior.CloseConnection), cmd.EndExecuteReader) .ContinueWith(reader=&gt; { //do some processing reader.Close(); }); .ContinueWith(_ =&gt; { lblStatus.Text="Done"; },TaskScheduler.FromCurrentSynchronizationContext()); </code></pre> <p>to read and process the data asynchronously and update the UI once processing finishes.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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