Concurrency 未来的完成与准备方法:Rust与基于运行时的语言

Concurrency 未来的完成与准备方法:Rust与基于运行时的语言,concurrency,rust,task,Concurrency,Rust,Task,我对Rust中异步调度和执行的“就绪”方法有一个疑问,因为它与基于运行时的语言(Python,Node.js)的“完成”方法有关(并与之形成对比)。我使用了“准备就绪”和“完成”这两个术语,这两个术语启发了这个问题 如果我没有弄错的话,Rust futures(自std futures)将在“准备就绪”方法下实施: 被包装在任务中,任务将被包装的未来的私有调用堆栈存储在内存中,以允许其中断和恢复,假设在该时间间隔内运行其他未来 由于一些i/o参与者调用该任务(通过该任务已针对相关i/o参与者注册

我对Rust中异步调度和执行的“就绪”方法有一个疑问,因为它与基于运行时的语言(Python,Node.js)的“完成”方法有关(并与之形成对比)。我使用了“准备就绪”和“完成”这两个术语,这两个术语启发了这个问题

如果我没有弄错的话,Rust futures(自
std futures
)将在“准备就绪”方法下实施:

  • 被包装在任务中,任务将被包装的未来的私有调用堆栈存储在内存中,以允许其中断和恢复,假设在该时间间隔内运行其他未来
  • 由于一些i/o参与者调用该任务(通过该任务已针对相关i/o参与者注册的回调),它们的包装任务会对其进行轮询
  • 当且仅当其任务已注册回调的任务链中的所有其他任务或i/o参与者由于其自己的未来已准备好进行轮询而被唤醒时,才返回一个值
  • 主要的区别——这可能解释了为什么Rust futures比基于运行时的同类产品更有效——是futures不会通过调用下一个任务自动将计算值传递到futures链的上一级。相反,由一系列任务中的最后一个继任者来触发其所有前任以级联方式相互轮询,计算最后一个未来的价值。因此,Rust中“准备就绪”方法的主要优势似乎与队列的主要优势相似:只要您足够快地消耗未来,数据就不会在堆栈中累积,内存消耗仍然很低


    现在,最后一个问题是:如果这个模型比一个模型更有效,在这个模型中,期货确实会在不等待最后一次后续投票的情况下创建自己的泡沫,那么为什么Python或Nodejs不遵循这种方法呢?直观地看,这种方法的优势似乎可以很好地转化为基于运行时的语言。这些语言是否因为不能足够快地使用未来的数据而转向“完成”替代方案

    我认为您没有正确描述两种模型之间的差异,也没有正确描述导致Rust选择“准备就绪”模型的主要好处

    基本区别是(如上所述):

    rust异步模型是基于拉的。而不是未来的存在 负责将数据推送到回调中,它依赖于 询问是否完整的其他问题

    设计的一个关键目标是,它应该提供一个——这要求使用futures编写异步代码应该具有与手动编写自己的事件循环和基于状态机的解决方案一样好的性能特征

    基于就绪性的模型的选择来自于这个需求:如果要使用基于完成的模型,未来的组合将需要相应的回调被堆分配(链接显示了为什么会这样)。堆分配是昂贵的,零成本抽象的目标将无法实现

    使用基于就绪性的模型,可以最小化甚至完全避免堆分配(对于一些没有堆的嵌入式环境尤其有益)

    该模型还有其他好处-其中之一是易于实现背压,您将其作为关键好处引用-但我不认为它们是选择该模型的决定性因素

    在解决了这个问题之后:

    最后一个问题是:这个模型是否比 模型中,期货确实会在不等待的情况下产生自己的泡沫 在最后一次后续投票中,为什么Python没有遵循这种方法 还是点头

    高级语言不倾向于提供提供零成本抽象所需的低级功能。例如,Javascript语言规范甚至不涉及堆栈或堆,尽管一些JS实现确实优化了堆栈上的局部变量,但程序员无法控制这一点。在为异步编程选择模型时,不需要堆分配就可以编写未来


    这并不是说其他一些好处在其他编程环境中可能没有用处——它们可能会有用——但由于大多数这些语言已经确定了基于完成的模型,并且由于它们没有相同的零成本抽象驱动力,可能没有兴趣重新审视设计。

    谢谢您的回复。你帮了我——我想——明白为什么我从博客文章中得到了错误的理解。让我检查一下:对于一个基于完成的模型,当你将一个“连接”回调传递给负责从一对期货的值中组合一个值的Future时,您需要堆分配各个值,因为否则您无法让未来负责组成单个值共享这些值的所有权?正确-您必须在正在加入的未来之间共享“加入”的状态。不仅如此,这些未来可能会从不同的线程运行。因此,您需要一个堆分配、同步、引用计数的对象。这也适用于其他形式的作文。非常感谢您的时间,这次交流给了我们启示!