gpt4 book ai didi

raku - Raku(do) 所依赖的延续的具体细节是什么?

转载 作者:行者123 更新时间:2023-12-03 14:20:04 28 4
gpt4 key购买 nike

在 1990 年代和 2000 年代,编程语言爱好者几乎没有讨论过分隔延续的话题。它最近重新成为编程语言讨论中的一个主要问题。
我希望有人至少可以权威地说出 Rakudo 背后的延续(与 Raku 相比)是否具有下面列出的六个特征中的每一个。在列表之后,我会多说一些我希望得到的答案。
从在线消息中逐字引用(带有格式修饰) [1] 由插入向 JVM 添加延续的工作的人编写:

  • 不对称 :当延续挂起或让出时,执行返回到调用者(Continuation.run())。对称延续没有调用者的概念。当他们让步时,他们必须指定另一个延续以将执行转移到。对称延续和非对称延续都不比彼此更强大,每个都可以用来模拟另一个。
  • 堆积如山 : 延续可以在调用堆栈中的任何深度挂起,而不是在延续是无堆栈时(如 C# 中的情况)在分隔上下文开始的同一子例程中。即延续有自己的堆栈,而不仅仅是一个子程序框架。有堆栈的延续比无堆栈的更强大。
  • 分隔 :continuation 捕获以特定调用开始的执行上下文(在我们的例子中,是某个 runnable 的主体)而不是整个执行状态,一直到 main() .带分隔符的延续严格来说比不带分隔符的延续( http://okmij.org/ftp/continuations/undelimited.html )更强大,后者被认为“没有实际用处”( http://okmij.org/ftp/continuations/against-callcc.html )。
  • 多提示 : 延续可以嵌套,在调用堆栈的任何地方,任何封闭的延续都可以挂起。这类似于 try/catch 块的嵌套,并抛出某种类型的异常,将堆栈展开到最近的处理它的 catch 而不仅仅是最近的 catch。嵌套延续的一个例子是在虚拟线程中使用类似 Python 的生成器。生成器代码可以执行阻塞 IO 调用,这将挂起封闭线程的延续,而不仅仅是生成器:https://youtu.be/9vupFNsND6o?t=2188
  • 一次性/不可重入 : 每次我们继续一个暂停的延续时,它的状态都会发生变化,我们不能从同一个暂停状态多次继续它(即我们不能回到过去)。这与可重入延续不同,每次我们暂停它们时,都会返回一个表示特定暂停点的新的不可变延续对象。 IE。延续是一个单一的时间点,每次我们继续它时,我们都会回到那个状态。可重入的延续严格来说比不可重入的更强大;也就是说,他们可以做一些完全不可能的事情,只需一次连续即可。
  • 可复制 :如果我们能够克隆一次性延续,我们可以提供与可重入延续相同的能力。即使每次我们继续它时延续都会发生变化,我们可以在继续创建该时间点的快照之前克隆它的状态,以便稍后返回。

  • Aiui continuations 没有直接暴露在 Raku 中,所以可能与 Raku 相关的正确答案(与 Rakudo 相对)是“没有延续”。但这对我来说并不清楚,所以在下文中,如果我很幸运,我会在其中描述我希望答案中的内容,我会假装在 Raku 的上下文中谈论它们是有道理的和乐堂是两个截然不同的领域。
    这是我想象的那种答案是可能的(尽管我只是有点疯狂地猜测实际情况):
  • “作为“100 年”语言设计,Raku 当前的底层语义 [执行?] 模型至少需要无堆栈一次性多提示分隔的延续。
  • 从理论上的观点来看,Raku 的设计永远不能扩展到要求延续是可克隆的,但理论上它可以扩展到要求它们是可堆叠的。
  • Rakudo 实现了当前所需的延续语义。
  • MoarVM 内置了对这些语义的支持,如果 Raku 的设计如此扩展,它可以实际跟踪理论上可能的需求扩展。
  • JVM 和 JS 后端有合适的 shims 来实现相同的目标,尽管会降低性能。 JVM 后端可以切换到使用 JVM 原生的延续(如果它得到它们)似乎是合理的,当然前提是它们满足要求,但我目前的印象是它实际上可能需要十年在我们需要考虑过那座桥之前,离开或更多。”

  • (或者类似的东西。)
    如果答案还提供了有关上述内容的更多详细信息,也许是一些代码链接,那将是一个特别棒的补充。
    类似地,如果答案包括几个简短的例子,说明这种持续能力如何在当前的 Raku 特征中出现,并推测它可能有一天,比如说 10 年后,如何在其他特征中出现,那么答案就会变得过分——顶级的辉煌。
    附注。感谢@Larry,他对事物的理解足够深刻,知道需要成为图片的一部分的延续;感谢 Stefan O'Rear 的贡献,包括我认为是一次性多提示分隔延续的初始实现;并感谢 jnthn 让梦想成真。
    脚注
    1 目前正在进行将延续作为第一类构造引入 JVM 的工作。这项工作的主要插入者是 Ron Pressler。以上基于 a message he wrote in November .

    最佳答案

    Rakudo 使用 continuation 作为两个特性的实现策略:

  • gather/take - 用于实现惰性迭代器
  • 制作 await关于线程池非阻塞

  • 实现的延续的特性遵循这些语言特性的要求。我将以与上面略有不同的顺序浏览它们,因为它易于解释。
  • 堆积如山 - 是的,因为我们需要能够做到takeawait在调用堆栈中相对于 gather 的任何深度或线程池 worker 的工作循环。例如,您可以在 gather 内部编写递归图遍历算法。然后 take每个遇到的节点。对于 await ,这是 Raku 与 await 之间差异的核心。和 await正如在许多其他语言中所见:您不必一直向上重构调用堆栈。
  • 分隔 - 是的。延续重置操作会安装一个标签(或“提示”),当我们进行延续控制操作时,我们会在这个分隔符处对堆栈进行切片。我无法想象如何在没有分隔的情况下实现所涉及的 Raku 功能。
  • 多提示 - 是的,这是必需的,因为您可以迭代 gather 提供的一个数据源另一个内部gather的实现,或者做一个 await内部 gather .
  • 不对称 - 继续执行后,在 reset 之后继续执行操作说明。在 await在这种情况下,我们去工作任务队列中寻找另一个任务,并在 take 中。如果我们回到 pull-one迭代器的方法,可以返回获取的值。我认为这种方法非常适合只有少数功能使用延续的语言。
  • 一次性/不可重入 - 是的,至少在 MoarVM 中,运行时的内存安全取决于此属性。它由原子比较和交换操作强制执行,因此如果两个线程要竞争调用延续,则只有一个线程会成功。没有 Raku 功能需要可重入延续所暗示的额外复杂性。
  • 可复制 - 不,因为没有 Raku 功能需要它。从理论上讲,就说“是的,我们可以做到”而言,这在 MoarVM 中实现并不是太糟糕,但我怀疑它会引发很多问题,例如“应该克隆多深”。如果你只是克隆了所有的调用记录和类似的,你仍然会共享 Scalar容器,Array s 等。

  • 据我了解 - 尽管我是从远处跟踪 - JVM 延续至少部分针对与 Raku await 相同的设计空间。机制已经存在,所以如果他们最终没有提供 Raku 需要的东西,我会感到惊讶。这显然会简化 Raku 代码到 JVM 的编译(目前它在执行代码生成时执行全局 CPS 转换,奇怪的是结果比我预期的要简单),而且几乎可以肯定它的性能也会好得多,因为需要转换从 JIT 编译器的角度来看,可能会掩盖很多事情。
    就代码而言,你可以看到 the current continuations implementation ,它使用 continuation data structure依次具有 memory management 的各种位.在撰写本文时,这些都已被显着重构,作为正在进行的调度程序工作所需的新调用堆栈表示的一部分;这些更改确实使使用 continuation 更有效率,但不会更改整个操作集。

    关于raku - Raku(do) 所依赖的延续的具体细节是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62817878/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com