Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I like this technique better. I'm using <code>TaskCompletionSource</code> to create output tasks for the incoming tasks. This is necessary because I want to return a <code>Task</code> before I even run it! The class below associates each input <code>Func(of Task(of Object))</code> with a <code>TaskCompletionSource</code> which is returned immediately and puts them into a queue.</p> <p>Elements from the queue are dequeued into a list of running tasks and a continuation sets the <code>TaskCompletionSource</code>. An invocation to <code>WhenAny</code> in a loop makes sure to move elements from the queue to the running list when room frees up. There's also a check to make sure that there isn't more than one <code>WhenAny</code> at a time, though it might have concurrency issues.</p> <p>To use, just replace synchronous functions like this:</p> <pre class="lang-vb prettyprint-override"><code>Task.Run(AddressOf MySyncFunction) 'possibly many of these </code></pre> <p>with this:</p> <pre class="lang-vb prettyprint-override"><code>Dim t1 As New Throttler(4) t1.Run(AddressOf MySyncFunction) 'many of these, but only 4 will run at a time. </code></pre> <p>For functions which already return a Task, it's important to convert those into functions that return Task so that the thottler can run them. Replace:</p> <pre class="lang-vb prettyprint-override"><code>NewTask = MyFunctionAsync() </code></pre> <p>with:</p> <pre class="lang-vb prettyprint-override"><code>NewTask = t1.Run(Function () return MyFunctionAsync()) </code></pre> <p>The class below also implements many different signatures for Throttler.Run() depending on whether the function is sync/async, has/hasn't input, has/hasn't output. Converting Task to Task(Of Output) is especially tricky!</p> <pre class="lang-vb prettyprint-override"><code>Class Throttler Property MaxCount As Integer Sub New(Optional MaxCount As Integer = 1) Me.MaxCount = MaxCount End Sub Private Running As New List(Of Task) Private Waiting As New Concurrent.ConcurrentQueue(Of System.Tuple(Of Func(Of Task(Of Object)), TaskCompletionSource(Of Object))) Private AlreadyWaiting As Boolean Async Sub MakeWaiter() If AlreadyWaiting Then Exit Sub AlreadyWaiting = True Do While Waiting.Count &gt; 0 Dim CurrentWait As System.Tuple(Of Func(Of Task(Of Object)), TaskCompletionSource(Of Object)) = Nothing Do While Running.Count &lt; MaxCount AndAlso Waiting.TryDequeue(CurrentWait) Dim NewFunc As Func(Of Task(Of Object)) = CurrentWait.Item1 Dim NewTask As Task(Of Object) = NewFunc() Dim CurrentTcs As TaskCompletionSource(Of Object) = CurrentWait.Item2 NewTask.ContinueWith(Sub(t2 As Task(Of Object)) CurrentTcs.SetResult(t2.Result) End Sub) Running.Add(NewTask) Loop If Waiting.Count &gt; 0 Then Dim Waiter As Task(Of Task) Waiter = Task.WhenAny(Running) Dim FinishedTask As Task = Await Waiter Await FinishedTask Running.Remove(FinishedTask) End If Loop AlreadyWaiting = False End Sub Function Run(f As Func(Of Task(Of Object))) As Task(Of Object) Dim NewTcs As New TaskCompletionSource(Of Object) Waiting.Enqueue(New System.Tuple(Of Func(Of Task(Of Object)), TaskCompletionSource(Of Object))(f, NewTcs)) MakeWaiter() Return NewTcs.Task End Function Function Run(Of TInput)(f As Func(Of TInput, Task), input As TInput) As Task Dim NewF As Func(Of Task) NewF = Function() As Task Return f(input) End Function Return Me.Run(NewF) End Function Function Run(Of TInput)(f As Func(Of TInput, Task(Of Object)), input As TInput) As Task(Of Object) Dim NewF As Func(Of Task(Of Object)) NewF = Function() As Task(Of Object) Return f(input) End Function Return CType(Me.Run(NewF), Task(Of Object)) End Function Function Run(f As Func(Of Task)) As Task Dim NewF As Func(Of Task(Of Object)) NewF = Function() As Task(Of Object) Return f().ContinueWith(Function(t As task) As Object Return Nothing End Function) End Function Return CType(Me.Run(NewF), Task(Of Object)) End Function Function Run(Of TInput)(f As Func(Of TInput, Object), input As TInput) As Task(Of Object) Dim NewF As Func(Of Task(Of Object)) NewF = Function() As Task(Of Object) Return Task.Run(Function() As Object Return f(input) End Function) End Function Return CType(Me.Run(NewF), Task(Of Object)) End Function Function Run(Of TInput)(f As Action(Of TInput), input As TInput) As Task Dim NewF As Func(Of Task) NewF = Function() As Task Return Task.Run(Sub() f(input) End Sub) End Function Return Me.Run(NewF) End Function Function Run(f As Func(Of Object)) As Task(Of Object) Dim NewF As Func(Of Task(Of Object)) NewF = Function() As Task(Of Object) Return Task.Run(Function() Return f() End Function) End Function Return CType(Me.Run(NewF), Task(Of Object)) End Function Function Run(f As Action) As Task Dim NewF As Func(Of Task) NewF = Function() As Task Return Task.Run(Sub() f() End Sub) End Function Return Me.Run(NewF) End Function End Class </code></pre>
    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