c# 5.0 中的新异步功能如何通过 call/cc 实现? [英] How could the new async feature in c# 5.0 be implemented with call/cc?

查看:19
本文介绍了c# 5.0 中的新异步功能如何通过 call/cc 实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在关注有关将在 c# 5.0 中的新 async 功能的新公告.我对延续传递风格和新的 c# 编译器对代码的转换有了基本的了解,就像来自 埃里克·利珀特的帖子:

I've been following the new announcement regarding the new async feature that will be in c# 5.0. I have a basic understanding of continuation passing style and of the transformation the new c# compiler makes to code like this snippet from Eric Lippert's post:

async void ArchiveDocuments(List<Url> urls)
{
  Task archive = null;
  for(int i = 0; i < urls.Count; ++i)
  {
    var document = await FetchAsync(urls[i]);
    if (archive != null)
      await archive;
    archive = ArchiveAsync(document);
  }
}

我知道有些语言通过 call-with-current-continuation (callcc) 在本地实现了延续,但我并不真正理解它是如何工作的或它究竟做了什么.

I know that some languages implement continuations natively, via call-with-current-continuation (callcc), but I don't really understand how that works or what it does exactly.

那么问题来了:如果安德斯等人.决定硬着头皮在 c# 5.0 中实现 callcc 而不是 async/await 特殊情况,上面的代码片段会是什么样子?

So here's the question: if Anders et al. had decided to bite the bullet and just implement callcc in c# 5.0 instead of the async/await special case, what would the above snippet look like?

推荐答案

原答案:

据我所知,您的问题是如果不是专门为基于任务的异步实现await",而是实现了更通用的 call-with-current-continuation 控制流操作,会怎样?"

Original answer:

Your question, as I understand it, is "what if instead of implementing "await" specifically for task-based asynchrony, rather, the more general control flow operation of call-with-current-continuation had been implemented?"

好吧,首先让我们考虑一下await"的作用.await"采用 Task 类型的表达式,获得一个等待器,并使用当前的延续调用等待器:

Well, first of all let's think about what "await" does. "await" takes an expression of type Task<T>, obtains an awaiter, and calls the awaiter with the current continuation:

await FooAsync()

变得有效

var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);

现在假设我们有一个操作符callcc,它将一个方法作为参数,并用当前的continuation 调用该方法.看起来像这样:

Now suppose we had an operator callcc which takes as its argument a method, and calls the method with the current continuation. That would look like this:

var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;

换句话说:

await FooAsync()

无非是

callcc FooAsync().GetAwaiter().BeginAwait;

这是否回答了您的问题?

Does that answer your question?

正如评论者指出的那样,下面的答案假定来自异步/等待功能的技术预览"版本的代码生成模式.实际上,我们在该功能的 Beta 版本中生成的代码略有不同,尽管 逻辑上 是相同的.目前的代码生成类似于:

As a commenter points out, the answer below assumes the code generation pattern from the "Technology Preview" version of the async/await feature. We actually generate slightly different code in the beta version of the feature, though logically it is the same. The present codegen is something like:

var task = FooAsync();
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
    awaiter.OnCompleted(somehow get the current continuation);
    // control now returns to the caller; when the task is complete control resumes...
}
// ... here:
result = awaiter.GetResult();
// And now the task builder for the current method is updated with the result.

请注意,这有点复杂,并处理您等待"已经计算出的结果的情况.如果您正在等待的结果实际上已经在内存中为您缓存,则无需经历将控制权交给调用者并从上次中断的地方再次接听的所有繁琐程序.

Notice that this is somewhat more complicated, and handles the case where you are "awaiting" a result that has already been computed. There's no need to go through all the rigamarole of yielding control to the caller and picking up again where you left off if the result that you are waiting for is in fact already cached in memory for you right there.

因此,await"和callcc"之间的联系并不像预览版中那么简单,但很明显我们实际上是在 awaiter 的OnCompleted"方法上执行 callcc.如果没有必要,我们只是不执行 callcc.

Thus the connection between "await" and "callcc" is not quite as straightforward as it was in the preview release, but it is still clear that we are essentially doing a callcc on the "OnCompleted" method of the awaiter. We just don't do the callcc if we don't have to.

作为这个答案

https://stackoverflow.com/a/9826822/88656

来自 Timwi 指出,call/cc 和 await 的语义并不完全相同;真正的"调用/cc 要求我们捕获"方法的整个延续包括其整个调用堆栈,或者等效地将整个程序重写为延续传球风格.

from Timwi points out, the semantics of call/cc and await are not quite the same; a "true" call/cc requires either that we "capture" the entire continuation of a method including its whole call stack, or equivalently that the whole program be rewritten into continuation passing style.

await"功能更像是合作通话/抄送";延续只捕获当前任务返回方法在等待点接下来要做什么?"如果任务返回方法的调用者要在任务完成后做一些有趣的事情,那么它可以自由地将它的延续注册为任务的延续.

The "await" feature is more like a "cooperative call/cc"; the continuation only captures "what is the current task-returning method about to do next at the point of the await?" If the caller of the task-returning method is going to do something interesting after the task is complete then it is free to sign up its continuation as the continuation of the task.

这篇关于c# 5.0 中的新异步功能如何通过 call/cc 实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆