How to use C#8 IAsyncEnumerable to async-enumerate tasks run in parallel

后端 未结 5 1834
孤独总比滥情好
孤独总比滥情好 2021-02-09 15:00

If possible I want to create an async-enumerator for tasks launched in parallel. So first to complete is first element of the enumeration, second to finish is second element of

5条回答
  •  孤独总比滥情好
    2021-02-09 15:22

    Here is a version that also allows to specify the maximum degree of parallelism. The idea is that the tasks are enumerated with a lag. For example for degreeOfParallelism: 4 the first 4 tasks are enumerated immediately, causing them to be created, and then the first one of these is awaited. Next the 5th task is enumerated and the 2nd is awaited, and so on.

    To keep things tidy, the Lag method is embedded inside the ParallelEnumerateAsync method as a static local function (new feature of C# 8).

    public static async IAsyncEnumerable ParallelEnumerateAsync(
        this IEnumerable> tasks, int degreeOfParallelism)
    {
        if (degreeOfParallelism < 1)
            throw new ArgumentOutOfRangeException(nameof(degreeOfParallelism));
    
        if (tasks is ICollection>) throw new ArgumentException(
            "The enumerable should not be materialized.", nameof(tasks));
    
        foreach (var task in Lag(tasks, degreeOfParallelism - 1))
        {
            yield return await task.ConfigureAwait(false);
        }
    
        static IEnumerable Lag(IEnumerable source, int count)
        {
            var queue = new Queue();
            using (var enumerator = source.GetEnumerator())
            {
                int index = 0;
                while (enumerator.MoveNext())
                {
                    queue.Enqueue(enumerator.Current);
                    index++;
                    if (index > count) yield return queue.Dequeue();
                }
            }
            while (queue.Count > 0) yield return queue.Dequeue();
        }
    }
    

    Note: this implementation is flawed regarding maintaining a consistent degree of parallelism. It depends on all tasks having similar completion durations. A single long running task will eventually drop the degree of parallelism to one, until it is completed.

提交回复
热议问题