準備完了と完了非同期IOメモリ使用量


12

Rustでの非同期IOの実装に関するこの講演を見ていましたが、Carlは2つの潜在的なモデルに言及しています。準備と完了。

準備モデル:

  • ソケットから読み取ることをカーネルに指示します
  • しばらく他のことをする…
  • カーネルは、ソケットの準備ができたときに通知します
  • あなたが読む(バッファを埋める)
  • 必要なことは何でもしてください
  • バッファーを解放します(Rustで自動的に発生します)

完了モデル:

  • カーネルが満たすようにバッファを割り当てます
  • しばらく他のことをする…
  • カーネルは、バッファがいっぱいになると通知します
  • データで必要なことを何でもする
  • バッファを解放する

レディネスモデルを使用するCarlの例では、使用可能なメモリを反復処理して、グローバルバッファを埋め、解放することで、メモリの使用量を大幅に減らすことができます。

今私の仮定:

ソケットが「準備完了」であると言われる内部(カーネル空間内)では、データは既に存在します。ネットワーク経由で(またはどこからでも)ソケットに入り、OSはデータを保持しています。

そのメモリ割り当てがレディネスモデルで魔法のように行われないというわけではありません。OSがそれをあなたから抽象化しているだけです。完了モデルでは、OSは、データが実際に流入する前にメモリを割り当てるように求めており、何が起きているかが明らかです。

準備モデルの修正版は次のとおりです。

  • ソケットから読み取ることをカーネルに指示します
  • しばらく他のことをする…
  • 修正:データはOSに送られます(カーネルメモリの一部)
  • カーネルは、ソケットの準備ができたことを通知します
  • 読み取ります(上記のカーネルバッファーとは別のバッファーを埋めます(または、ポインターを取得しますか?))
  • 必要なことは何でもしてください
  • バッファーを解放します(Rustで自動的に発生します)

/私の仮定

私はたまたまユーザースペースプログラムを小さく保つのが好きですが、実際にここで何が起こっているのかを明確にしたかったのです。1つのモデルが本質的に少ないメモリを使用したり、より高いレベルの同時IOをサポートしたりすることはありません。私はこれについての考えとより深い説明を聞きたいです。


私もそのYouTubeトークからここに到着しました。どのようにIO非同期またはどのようにイベントループを実装する方法について学ぶ人のために、錆のチームは「Aysncインタビュー」のこのプレイリストがあるここコミュニティから非常に精通して人々のインタビューを
cacoder

回答:


5

レディネスモデルでは、メモリの消費量はアプリケーションが消費していないデータの量に比例します。

完了モデルでは、メモリ消費は未処理のソケット呼び出しの量に比例します。

ほとんどがアイドル状態のソケットが多数ある場合、レディネスモデルはより少ないメモリを消費します。

完了モデルには簡単な修正があります。1バイトの読み取りを開始します。これは小さなバッファのみを消費します。読み取りが完了すると、残りのデータを取得する別の(おそらく同期)読み取りを発行します。

一部の言語では、完了モデルの実装は非常に簡単です。私はそれが良いデフォルトの選択だと思います。


1

完了モデルでは、OSは、データが実際に流入する前にメモリを割り当てるように求めており、何が起きているかが明らかです。

しかし、スペースを割り当てたよりも多くのデータが入った場合はどうなりますか?カーネルは、データをドロップしないように、独自のバッファーを割り当てる必要があります。(たとえば、これがusrの回答に記載されている1バイトの読み取りトリックが機能する理由です。)

トレードオフは、完了モデルはより多くのメモリを消費しますが、バッファを保持することでハードウェアが直接出入りできることを意味するため、コピー操作を(場合によっては)少なくすることもできます。また、完了モデルは、少なくともWindowsのIOCPの場合、別のスレッドで実際のコピー操作(存在する場合)を実行する傾向があるのではないかと疑っていますが、レディネスモデルは非ブロッキングread()またはwrite()コール。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.