I have some code of the following form:
static async Task DoSomething(int n)
{
...
}
static void RunThreads(int totalThreads, int throttle)
{
var tasks = new List<Task>();
for (var n = 0; n < totalThreads; n++)
{
var task = DoSomething(n);
tasks.Add(task);
}
Task.WhenAll(tasks).Wait(); // all threads must complete
}
Trouble is, if I don't throttle the threads, things start falling apart. Now, I want to launch a maximum of throttle
threads, and only start the new thread when an old one is complete. I've tried a few approaches and none so far has worked. Problems I have encountered include:
- The
tasks
collection must be fully populated with all tasks, whether active or awaiting execution, otherwise the final.Wait()
call only looks at the threads that it started with. - Chaining the execution seems to require use of
Task.Run()
or the like. But I need a reference to each task from the outset, and instantiating a task seems to kick it off automatically, which is what I don't want.
How to do this?
Here are some extension method variations to build on Sriram Sakthivel answer.
In the usage example, calls to
DoSomething
are being wrapped in an explicitly cast closure to allow passing arguments.Stephen Toub gives the following example for throttling in his The Task-based Asynchronous Pattern document.
Microsoft's Reactive Extensions (Rx) - NuGet "Rx-Main" - has this problem sorted very nicely.
Just do this:
Job done.
If I understand correctly, you can start tasks limited number of tasks mentioned by
throttle
parameter and wait for them to finish before starting next..To wait for all started tasks to complete before starting new tasks, use the following implementation.
To add tasks as on when it is completed you can use the following code
The simplest option IMO is to use TPL Dataflow. You just create an
ActionBLock
, limit it by the desired parallelism and start posting items into it. It makes sure to only run a certain amount of tasks at the same time, and when a task completes, it starts executing the next item: