迭代器不只是一种遍历集合的方式(这只是最简单的用例之一),相反迭代器是返回序列的一种方式。这个序列甚至可能是无限的,或者单次的operation的cost很巨大比如load item,process。比如返回质数的list,我们没有办法返回一个无限长度的列表并使用前100个项。所以有时它必须是惰性的,每次执行完之后交还给caller。返回一个集合与返回一个即迭代是完全不同的概念。
看个例子:
var Fishes = ProduceFish(5);
Console.WriteLine("Cheif: start to cook.");
Console.WriteLine("**********************");
foreach (int i in Fishes)
{
Console.WriteLine($"Cook the Fish: {i}");
}
IEnumerable<int> ProduceFish(int upto)
{
Console.WriteLine("Helper helps to clean the fish ");
for (int i = 0; i <= upto; i += 1)
{
Console.WriteLine("**********************");
Console.WriteLine($"Helper cleans fish {i}");
yield return i;
Console.WriteLine($"Cook fish {i} finished, Helper move to next fish");
}
Console.WriteLine("End of Bussiness, Helper starts to clean the kitchen");
}
输出:
可以看到Helper每次只处理一条鱼,就会交给Cheif进行处理,而不是把5条鱼都处理完了之后,一块返回做处理。
我们可以给每条鱼的处理加上2s的处理时间,使用 IAsyncEnumerable<T>替换掉 IEnumerable<T>来获得异步的iterator:
var Fishes = ProduceFish(5);
Console.WriteLine("Cheif: start to cook.");
Console.WriteLine("**********************");
await foreach (int i in Fishes)
{
Console.WriteLine($"Cook the Fish: {i}");
}
async IAsyncEnumerable<int> ProduceFish(int upto)
{
Console.WriteLine("Helper helps to clean the fish ");
for (int i = 0; i <= upto; i += 1)
{
Console.WriteLine("**********************");
Console.WriteLine($"Helper cleans fish {i}");
yield return await TakeTimeToCleanFish(i);
Console.WriteLine($"Cook fish {i} finished, Helper move to next fish");
}
Console.WriteLine("End of Bussiness, Helper starts to clean the kitchen");
}
async Task<int> TakeTimeToCleanFish(int i)
{
await Task.Delay(2000);
Console.WriteLine($"It took 2s to clean the fish {i}");
return i;
}
每次处理过程会以2s为间隔输出: