io_uringが何なのかは以下の記事が詳しかったです。Qiitaざっくり、io_uringはLinuxで非同期IOをするためのAPIです。ユーザランドとカーネルランドで2つのキューを共有し、そこを通じて会話をします。1つのキューはユーザランドからカーネルへのリクエストの提出用、もう1つのキューはカーネルからユーザランドへの完了の通知用です。epollを制御するためにfdもあります。こんなイメージですかね。kernelそれぞれのキューはリングバッファで実装されています。io_uringではIO処理の依頼とその完了待ちが分離されているので処理を発行しておいて自分のタイミングで結果を受け取ることができます。3つのIO処理をするときにio_uringなしに普通の処理をやろうとすると3回分IOの待ちが発生します。||<---+しかしio_uringを使えばIOリクエストを矢継ぎ早に送れるので待ち時間を短縮できます。||<---+|<---+|<---+特にSSDだとコマンドキューにどれだけ命令を詰め込めるかが勝負らしい(?)のでio_uringだと有利なのかもしれません。いうことでio_uringを使ってIO処理を高速化してみましょう。liburingio_uringはLinuxのAPIですが、そのまま使うにはいささか手間が大きいです。今までカーネルで全てやってきたことをユーザでコントロールできるようにするということはユーザでやることが増えるということでもあります。そこでio_uringを簡単に使えるライブラリとしてliburingがあります。axboe/liburingUbuntuならaptで入ります。liburing-devliburingの有無で使い勝手がどう違うかは以下のリポジトリが参考になりました。seriesまあ、今回私はRustのラッパを使うのでliburingは関係ないんですけどね。Rustからio_uringを使ってみるということでio_uringを使ってみましょう。Rustからだといくつかラッパが存在するようですがTokioのio_uringラッパを使ってみましょう。Rustこれはliburingを使わずにlibcのio_uringを直接ラップしたライブラリです。書かれたファイルを作ってみます。今回のコード全体は以下に置いておきます。KeenS/io-uring-write-file以後は重要なところだけを拾って解説していきます。標準ライブラリでの実装io_uringを使ずに標準ライブラリだけで書いたシンプルなコードであれば以下のように書けるでしょう。file.write_all(&DATA)?;}これと同等のことをio_uringで実装します。io-uringを使った実装io_uringで書き直してみます。ファイルを開いておきましょう。File::create("iouring.text")?;そしてio_uringを初期化します。IoUring::new(2048)?;引数はリングバッファのサイズです。2048という数値はまあ、なんか雰囲気で決めました。Linuxのio_uringではsubmitのキュー(sq)とcompletionのキュー(cq)それぞれ長さを指定できるはずですがTokioのバインディングでは両方とも同じ長さを指定しているようです。上の方でio_uringにはfd、sq、cqがあるといいましたが、Tokioのバインディングも3つのコンポーネントが取り出せます。uring.split();submitterはfd経由でsubmissionを管理するからのネーミングなんでしょう。DATA.len();タスクを発行したときに完了まで待たないので完了したタスクを管理する変数を別途用意します。0;さて、ここからIOリクエストを提出する段に入ります。して、以下の3行でIOリクエストを提出できます。いうのがTokioのバインディングのユニークな点で、その時点で空いているキューのビューを提供します。一瞬「それスレッドセーフじゃなくね?」って思いますがRustなので大丈夫です。所有権システムが守ってくれます。一気に複数のIOリクエストを溜めて一気に提出できます。回数は少ない方がカーネルとのやり取りが減って速そうなので1024回分のリクエストを溜めて一気に送ってみます。}}submitter.submit()?;つまり、全体はこういうイメージです。