Consider the following program, which uses TPL Dataflow. Hence, ActionBlock comes from the Dataflow library.
internal static class Program
{
public static async Task Main(string[] args)
{
var actionBlock = new ActionBlock<int>(async i =>
{
Console.WriteLine($"Started with {i}");
await DoSomethingAsync(i);
Console.WriteLine($"Done with {i}");
});
for (int i = 0; i < 5; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
}
private static async Task DoSomethingAsync(int i)
{
await Task.Delay(1000);
}
}
The output of this program is:
Started with 0
Done with 0
Started with 1
Done with 1
Started with 2
Done with 2
Started with 3
Done with 3
Started with 4
Done with 4
Reason is that the ActionBlock only starts processing the next task when the previous asynynchronous task was finished.
How can I force it to start processing the next task, even though the previous wasn't fully finished. MaxDegreeOfParallelism isn't an option, as that can mess up the order.
So I'd like the output to be:
Started with 0
Started with 1
Started with 2
Started with 3
Started with 4
Done with 0
Done with 1
Done with 2
Done with 3
Done with 4
I could get rid of the async/await and replace it with ContinueWith. But that has two disadvantages:
- The ActionBlock think it's done with the message immediately. An optional call to
Complete()would result in the pipeline being completed directly, instead of after the asynchronous action to be completed. - I'd like to add a
BoundedCapacityto limit the amount of messages currently still waiting to be fully finished. But because of 1. thisBoundedCapacityhas no effect.