【发布时间】:2014-08-05 07:21:46
【问题描述】:
假设我有一个异步获得的整数序列。
async Task<int> GetI(int i){
return await Task.Delay(1000).ContinueWith(x => i);
}
我想在该序列上创建一个生成器,如果该序列是同步的,我会这样做:
IEnumerable<int> Method()
{
for (var i = 0; i < 100; i++)
{
yield return GetI(i); // won't work, since getI returns a task
}
}
所以,我认为类比是使生成器异步并从中产生:
async Task<IEnumerable<int>> Method()
{
for (var i = 0; i < 100; i++)
{
yield return await Task.Delay(1000).ContinueWith(x => i);
}
}
这是行不通的,因为 yield 的方法必须返回 IEnumerable 987654330@s 或作废。
现在,我意识到我可以简单地删除等待并返回 IEnumerable<Task<int>> 但这对我没有帮助,因为迭代会在任何数据准备好之前继续询问数据,所以它不能解决我的问题。
- 有没有什么方法可以很好地将枚举和任务与语言给我的 await 和 yield 的糖很好地混合在一起?
- 有什么方法可以很好地消耗它吗?
(通过在线搜索,我怀疑第一个问题的答案是错误的,第二个问题是观察者/可观察的,但我找不到任何规范的参考资料,我对最好的方法感兴趣用 C# 实现这个模式)
【问题讨论】:
-
您实际上是想获得
Task<IEnumerable<int>>,还是IEnumerable<Task<int>>?后者更容易实现......但目前尚不清楚您实际上想要摆脱什么。 -
(顺便说一句,我明白在这种情况下表达你想要实现的目标可能非常困难。)
-
@JonSkeet 在听起来很愚蠢的机会上,我认为我正在尝试获得
Task<IEnumerable<Task<int>>>,我想获得一个我会等待的迭代器最初,然后在每次迭代时等待。但是,IEnumerable<Task<int>>也是可以接受的,问题是正如我在问题中提到的那样,IEnumerable 将在消费者身上同步消耗,我想在每次迭代中等待它,然后再消耗下一个元素。我想知道是否有一种聪明的方法可以做到这一点,它不涉及常规的 for 循环,在那里await暂停迭代。 -
@BenjaminGruenbaum, this question 密切相关。 AFAICT,你想要做的是一个很棒的 C# 语言 + LINQ 运行时特性,但它还不可用。另请查看 Stephen Toub 的 "Tasks, Monads, and LINQ"。
-
您正在寻找类似 @987654337@ 的东西,它公开了每个元素的异步性。
标签: c# asynchronous async-await generator promise