准备就绪与完成异步IO内存使用情况?


12

我看这次谈话有关实现异步IO在锈和卡尔提到了两个潜在的车型。准备和完成。

准备模型:

  • 您告诉内核您要从套接字读取
  • 暂时做其他事情……
  • 内核会告诉您套接字准备就绪的时间
  • 您阅读(填充缓冲区)
  • 做你需要的一切
  • 释放缓冲区(Rust自动发生)

完成模型:

  • 您为内核分配缓冲区以填充
  • 暂时做其他事情……
  • 内核会告诉您何时缓冲区已满
  • 对数据做您需要做的一切
  • 释放缓冲区

在使用准备模型的卡尔例如,你可以遍历准备插槽填充和释放一个全球性的缓冲,这使得它看起来像它会使用很多的内存更少。

现在我的假设是:

在底层(在内核空间中),当套接字被称为“就绪”时,数据已经存在。它已通过网络(或从任何地方)插入套接字,并且OS保留了数据。

这似乎并没有在准备模型中神奇地发生内存分配。只是操作系统正在从您那里提取它。在完成模型中,操作系统要求您在数据实际流入之前分配内存,这很明显正在发生。

这是我对“就绪模型”的修订版:

  • 您告诉内核您要从套接字读取
  • 暂时做其他事情……
  • 修订:数据进入操作系统(内核内存中的某个位置)
  • 内核告诉您套接字已准备好
  • 阅读(填充另一个与上述内核缓冲区分开的缓冲区(或者得到指向它的指针?))
  • 做你需要的一切
  • 释放缓冲区(Rust自动发生)

/我的假设

我碰巧喜欢将用户空间程序保持在很小的位置,但是我只是想澄清一下实际情况。我看不到一个模型会固有地使用更少的内存或支持更高级别的并发IO。我很想听听对此的想法和更深入的解释。


我也是从YouTube演讲中来到这里的。对于任何了解异步IO或如何实现事件循环的人,Rust团队都会在此播放“ Aysnc访谈”播放列表,在此采访社区中知识渊博的人们
cacoder

Answers:


5

在就绪模型中,内存消耗与应用程序未使用的数据量成正比。

在完成模型中,内存消耗与未完成的套接字调用的数量成比例。

如果有许多套接字大部分是空闲的,那么就绪模型将消耗较少的内存。

完成模型有一个简单的解决方法:启动一个1字节的读取。这仅消耗很小的缓冲区。读取完成后,将发出另一个(可能是同步的)读取,以获取其余数据。

在某些语言中,完成模型的实现极为简单。我认为这是一个很好的默认选择。


1

在完成模型中,操作系统要求您在数据实际流入之前分配内存,这很明显正在发生。

但是,如果输入的数据多于分配的空间,会发生什么?内核仍然必须分配自己的缓冲区,以免丢失数据。(例如,这就是为什么usr答案中提到的1字节读取技巧起作用的原因。)

折衷方案是,尽管完成模型消耗更多的内存,但它也可以(有时)执行较少的复制操作,因为保留缓冲区意味着硬件可以直接在其中进行DMA访问。我还怀疑(但不太确定)完成模型倾向于在另一个线程上进行实际的复制操作(如果存在),至少对于Windows的IOCP而言,而就绪模型则将其作为非阻塞read()或非阻塞的一部分进行。write()呼叫。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.