using System.Collections.Generic;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
public static class Program
public static async Task Main()
var sequence_A = Range("A{0}", 1, 5);
var sequence_B = Range("B{0}", 1, 3);
var sequence_C = Range("C{0}", 1, 7);
var merged = Interleave(sequence_A, sequence_B, sequence_C);
await foreach (var item in merged) { Console.WriteLine(item); await Task.Delay(100); }
public static IAsyncEnumerable<T> Interleave<T>(params IAsyncEnumerable<T>[] sources) =>
Interleave(default, sources);
public static async IAsyncEnumerable<T> Interleave<T>([EnumeratorCancellation] CancellationToken token, IAsyncEnumerable<T>[] sources)
var enumerators = new List<(IAsyncEnumerator<T> e, Task<bool> t)>(sources.Length);
for(var i = 0; i < sources.Length; i++)
var e = sources[i].GetAsyncEnumerator(token);
enumerators.Add((e, e.MoveNextAsync().AsTask()));
var taskResult = await Task.WhenAny(enumerators.Select(tuple => tuple.t));
var ind = enumerators.FindIndex(tuple => tuple.t == taskResult);
if(ind == -1) throw new Exception("ind was "+ind);
var tuple = enumerators[ind];
enumerators.RemoveAt(ind);
yield return tuple.e.Current;
enumerators.Add((tuple.e, tuple.e.MoveNextAsync().AsTask()));
await tuple.e.DisposeAsync();
} while (enumerators.Count > 0);
for(var i = 0; i < enumerators.Count; i++)
await enumerators[i].e.DisposeAsync();
static async IAsyncEnumerable<string> Range(string text, int start, int count) {
for (int i = 0; i < count; i++)
var delayTask = Task.Delay(50);
yield return string.Format(text, start + i);