对迭代方法进行“迭代”

时间:2011-12-08 14:56:52

标签: pattern-matching duck-typing async-ctp c#-5.0

有关异步CTP的一些相关问题:

  • 我可以使用IEnumerable<T>然后使用枚举器方法T和{{1}来迭代迭代器块(GetEnumerator()收益率返回MoveNext()) }。 Current()方法的模拟是什么?非async调用方法如何接收和处理任何async ed项,然后await?你能提供一个简短的例子吗?我只是没有看到它。

  • 此外,在以下示例ContinueWith()方法中,async具有MyAwaitable方法。如果GetAwaiter()返回GetAwaiter()string不是THuh,则编译器不会抱怨。 stringTHuh之间存在哪些类型约束/期望?

    GetAwaiter()
  • 请解释C#规范草案的以下行。 async Task<THuh> DoSomething() { var x = await new MyAwaitable("Foo"); var y = await new MyAwaitable("Bar"); return null; } 方法应该async Task<T> return永远不会被使用吗?我看到一些似乎不符合此规则的示例 - 返回值似乎可以访问,值是非默认值。这个值无法访问吗?如果是这样,为什么尴尬的难以接近的退货声明?

  

在某个default(T)的返回类型为Task<T>的异步函数中,   return语句必须具有隐式表达式   可转换为T,并且主体的端点必须无法访问。

  • 规范说“所有GetAwaiter,IsCompleted,OnCompleted和GetResult都是”非阻塞的“ - 那么在什么方法中应该定义(可能)长时间运行的操作?

谢谢!

2 个答案:

答案 0 :(得分:7)

  

我正在尝试使用Iterator Blocks转换继续传递(非常但很成功)并将其转换为使用异步。我想我正在以新的方式战斗。了解这种变化感觉就像拆开3英寸宽的魔术贴条一样。

我能理解你的感受。我不鼓励人们尝试用迭代器块来构建CPS,因为无论迭代器和CPS的共同基础机制是什么,它都不适合。迭代器块旨在为快速制作将数据结构转换为序列或将序列转换为不同序列的方法感觉良好;它们并非旨在解决电流持续呼叫的一般问题。

就此而言,async / await也不是精确调用电流继续,尽管它显然更接近一个数量级。 Async / await旨在使基于任务的异步更容易;它通过将代码重写为延续传递样式的形式来实现,这是一个实现细节。

我在相关主题上写的这个答案可能有所帮助:

How could the new async feature in c# 5.0 be implemented with call/cc?

我怀疑你所遇到的概念性问题是在迭代器风格的异步中,“orchestrator” - 当迭代器块从它停止的地方恢复时计算出的东西 - 你的代码。你编写了一些代码,然后决定何时调用MoveNext来抽取迭代器。使用基于任务的异步,其他一些代码可以为您完成。当任务完成时,将该事实发布到某处的消息队列的几率很好,然后当泵出消息队列时,继续将被激活并返回结果。您可以指出代码中没有明确的“MoveNext”;相反,任务已经完成并知道自己的继续这一事实足以确保将继续放在工作队列中以便最终执行。

如果您有更多问题,我建议您将其发布在SO和/或异步论坛上。

答案 1 :(得分:1)

DoSomething示例中,编译器没有抱怨,因为MyAwaitable的GetResult方法的类型与THuh无关。与THuh相关的声明为return null;

THuh类似的IEnumerable关键字为awaitforeach需要一种适合某种模式的类型,await也是如此。一种是消耗等待类型的机制,另一种是消耗可枚举类型。

另一方面,迭代器块(foreachyield return)是定义可枚举类型的机制(通过编写方法而不是显式声明类型)。这里的类比是yield break关键字。

要详细说明asyncasync之间的类比,请注意返回yield return的迭代器块可以包含语句IEnumerable<int>,类似地,返回{的async方法{1}}可以包含语句yield return 42;。请注意,在这两种情况下,返回表达式的类型不是方法的返回类型,而是方法返回类型的类型参数


如果你还没有这样做,你真的应该阅读Eric Lippert关于这些主题的博客:

http://blogs.msdn.com/b/ericlippert/archive/tags/Async/

http://blogs.msdn.com/b/ericlippert/archive/tags/Iterators/

此外,如果这个概念对你来说是新的(就像我一样),那么除了Async系列中的那些之外的延续传递风格的帖子会很有用:

http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+style/


最后,有关示例,请参阅Eric's blog post linking to his MSDN article and related articles in the same issue和Bill Wagner在http://msdn.microsoft.com/en-us/vstudio/hh533273的后续文章

修改

  

我看到一些似乎不遵循此规则的示例 - 返回值似乎可以访问,值是非默认值。这个值无法访问吗?如果是这样,为什么尴尬的难以接近的退货声明?

短语“正文的端点必须无法访问”意味着您必须有一个return语句。正文的端点位于return语句之后,并且由return语句无法访问。使用普通int返回方法的示例:

Task<int>

编辑2

这是一个计算字符串后半部分的awaiter的简短例子。该示例传递一个将结果打印到控制台的延续。这不是线程安全的!

yield return 42;