Task-based Asynchronous Pattern - WhenAllOrErrorBatched
This is a variant of WhenAllorError that a colleague asked me about. His scenario was that he had a lot of tasks to complete but since they all involved making HTTP requests to other servers he did not want to start them all at once but rather start a few and then as they completed start a few more. That's how I came up with WhenAllOrErrorBatched. The idea is that instead of giving it a list of tasks you provide a batchSize (number of parallel tasks) and a function that returns new tasks that will be called until it returns null.
1: public async static Task<T[]> WhenAllOrErrorBatched<T>(
2: int batchSize, Func<Task<T>> nextTask)
3: {
4: var result = new List<T>(batchSize);
5: var pending = new List<Task<T>>(batchSize);
6: bool pendingTasks = true;
7: while (true)
8: {
9: while (pendingTasks && pending.Count < batchSize)
10: {
11: var task = nextTask();
12: if (task == null)
13: {
14: pendingTasks = false;
15: break;
16: }
17:
18: pending.Add(task);
19: }
20:
21: if (pending.Count == 0)
22: {
23: break;
24: }
25:
26: await Task.WhenAny(pending);
27:
28: for (int i = 0; i < pending.Count; i++)
29: {
30: if (pending[i].IsCompleted)
31: {
32: result.Add(pending[i].Result);
33: pending.RemoveAt(i);
34: i--;
35: }
36: }
37: }
38:
39: return result.ToArray();
40: }