Gab*_*art 19 c# asynchronous callcc continuation-passing async-await
我一直在关注asyncc#5.0中新功能的新公告.我对继续传递样式以及新的c#编译器对Eric Lippert的帖子中的代码片段所做的转换有基本的了解:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我知道有些语言通过call-with-current-continuation(callcc)本地实现continuation ,但我真的不明白它是如何工作的或它究竟是做什么的.
所以这就是问题:如果安德斯等人.已经决定咬紧牙关,只是callcc在c#5.0而不是async/ await特殊情况下实现,上面的代码片段会是什么样子?
Eri*_*ert 28
正如我所理解的那样,你的问题是"如果不是实现"等待"专门用于基于任务的异步,而是实现了与电流继续呼叫的更一般的控制流操作?"
好吧,首先让我们考虑一下"等待"的作用."await"采用类型的表达式Task<T>,获取awaiter,并使用当前的continuation调用awaiter:
await FooAsync()
Run Code Online (Sandbox Code Playgroud)
变得有效
var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);
Run Code Online (Sandbox Code Playgroud)
现在假设我们有一个运算符callcc,它将一个方法作为参数,并使用当前的continuation调用该方法.这看起来像这样:
var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;
Run Code Online (Sandbox Code Playgroud)
换一种说法:
await FooAsync()
Run Code Online (Sandbox Code Playgroud)
无非就是
callcc FooAsync().GetAwaiter().BeginAwait;
Run Code Online (Sandbox Code Playgroud)
这是否回答你的问题?
正如评论者指出的那样,下面的答案假设来自async/await功能的"技术预览"版本的代码生成模式.我们实际上在该功能的测试版中生成了稍微不同的代码,但从逻辑上讲它是相同的.目前的codegen是这样的:
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.
Run Code Online (Sandbox Code Playgroud)
请注意,这有点复杂,并处理您"等待"已经计算过的结果的情况.如果您正在等待的结果实际上已经在内存中缓存,那么就没有必要通过所有对控制者产生控制的严格控制并再次接收.
因此,"await"和"callcc"之间的连接并不像在预览版本中那样简单,但我们仍然清楚地知道我们基本上在awaiter的"OnCompleted"方法上执行callcc.如果我们不需要,我们就不会做callcc.
作为这个答案
Timwi指出,call/cc和await的语义并不完全相同; 一个"真正的"调用/ cc需要我们"捕获" 一个方法的整个延续,包括它的整个调用栈,或者相当于整个程序被重写为延续传递样式.
"等待"功能更像是"合作呼叫/ cc"; 延续只捕获"当前任务返回方法在等待点下一步做什么?" 如果任务返回方法的调用者在任务完成后要做一些有趣的事情,则可以自由地将其继续作为任务的继续进行注册.