Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Note:</strong> I leave this here for legacy. Don't do it this way because there will be too many tasks waiting on the <code>WhenAny</code> simultaneously. And the stack will get deep.</p> <p>Based on this code by Stephen Toub:</p> <pre><code>const int CONCURRENCY_LEVEL = 15; Uri [] urls = …; int nextIndex = 0; var imageTasks = new List&lt;Task&lt;Bitmap&gt;&gt;(); while(nextIndex &lt; CONCURRENCY_LEVEL &amp;&amp; nextIndex &lt; urls.Length) { imageTasks.Add(GetBitmapAsync(urls[nextIndex])); nextIndex++; } while(imageTasks.Count &gt; 0) { try { Task&lt;Bitmap&gt; imageTask = await Task.WhenAny(imageTasks); imageTasks.Remove(imageTask); Bitmap image = await imageTask; panel.AddImage(image); } catch(Exception exc) { Log(exc); } if (nextIndex &lt; urls.Length) { imageTasks.Add(GetBitmapAsync(urls[nextIndex])); nextIndex++; } } </code></pre> <p>I wrote this:</p> <pre class="lang-vb prettyprint-override"><code>Private ThrottleGroups As New Dictionary(Of Object, List(Of Task)) Public Async Function ThrottleAsync(Of TResult)(ByVal f As Func(Of Task(Of TResult)), GroupId As Object, MaxCount As Integer) As Task(Of TResult) If Not ThrottleGroups.ContainsKey(GroupId) Then ThrottleGroups.Add(GroupId, New List(Of Task)) End If If ThrottleGroups(GroupId).Count &lt; MaxCount Then Dim NewTask As Task(Of TResult) = f() ThrottleGroups(GroupId).Add(NewTask) Return Await NewTask Else Dim FinishedTask As Task = Await Task.WhenAny(ThrottleGroups(GroupId)) ThrottleGroups(GroupId).Remove(FinishedTask) Return Await ThrottleAsync(f, GroupId, MaxCount) End If End Function </code></pre> <p>To use, just replace:</p> <pre class="lang-vb prettyprint-override"><code>ExampleTaskAsync(param1, param2) </code></pre> <p>with:</p> <pre class="lang-vb prettyprint-override"><code>Dim f As Func(Of Task(Of Integer)) f = Function() Return ExampleAsync(param1, param2) End Function Const CONCURRENT_TASKS As Integer = 4 Return ThrottleAsync(f, "ExampleAsync", CONCURRENT_TASKS) </code></pre> <p>Notice that we have to wrap the call to the task in a function <code>f</code> because otherwise we would be already starting the Task. The second parameter to ThrottleAsync is any object that identifies the "group"; I used a string. All asynchronous tasks in the same "group" are limited to <code>CONCURRENT_TASKS</code> tasks, in this case 4.</p> <p>Here's sample code that show how only four threads run at a time. <code>All Ready!</code> displays immediately because the subroutine is asynchronous. Also, even if the threads start or end out of order, the "output" lines will still be in the same order as the input.</p> <pre class="lang-vb prettyprint-override"><code>Dim results As New List(Of Task(Of Integer)) For i As Integer = 0 To 20 Dim j As Integer = i Dim f As Func(Of Task(Of Integer)) f = Function() As Task(Of Integer) Return Task.Run(Function() As Integer Debug.WriteLine(DateTime.Now &amp; "Starting " &amp; j) System.Threading.Thread.Sleep(5000) Debug.WriteLine(DateTime.Now &amp; "Ending " &amp; j) Return j End Function) End Function Const CONCURRENT_UPLOADS As Integer = 4 results.Add(ThrottleAsync(f, "PutOjbectAsync", CONCURRENT_UPLOADS)) Next Debug.WriteLine("all ready!") For Each x As Task(Of Integer) In results Debug.WriteLine(DateTime.Now &amp; "Output: " &amp; Await x) Next </code></pre>
 

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