プロセス間通信を利用して速度向上を目指したメモ

やるまで

先日 result-queue というツールを作成しました。

このシェルスクリプト製ツールの機能は、ざっと説明するとこんな感じです。

  • 主要な実行オプションとして「シェル用のコマンド」「キューファイル」「出力行数」がある。
  • 実行すると「キューファイル」の存在をチェックし、なければ「シェル用のコマンド」を実行する。実行結果は「出力行数」に従って出力され、余った行は「キューファイル」に保存される。
  • 「キューファイル」の残りが「出力行数」に満たない場合は、満たなくなったところで再度コマンドを実行する。

何を目的に作ったかというと、今データベースを利用するツールを作っていまして、そこからランダムなレコードを取得するときのためです。

巨大なデータベースからのランダム選択というのは基本的に重く、複雑な判定が絡むとさらに鈍くなります。そのくせ(データの傾向やクエリにもよるのかもしれませんが)、一度の処理でたくさんのレコードを取るときの速度と、ひとつのレコードを取るときの速度の差がそう大きくない。

だから先にたくさん取っておいて、小さめのキューファイルとして保持しておこうという、そういう狙いで作成しました。

これを導入することで、毎回データベースから直接検索するよりも明らかに速度は改善しました。

しかし、素早く動作するようになったとはいっても「まだいけるんじゃないか」感が残っています。

現在 (バージョン 1.2) のキューファイルを消費するたびにキューファイル自身を更新する仕様は、キューファイルの容量が数キロバイト程度であれば問題ありませんが、大きくなると書き込みのコストが高くなります。

じゃあ書き込みをしないようにすればいいじゃないか。

さらにいえば読み込むのは一度だけで、変数に保持しっぱなしにすれば…。

ということで、デーモン化して、プロセス間通信をしてみればどうだろうという発想に行き着いたのでした。

やった

テスト用に作成したのは、このシェルスクリプトです。

mem-echo

仕様としては、以下のような感じです。

  • STDIN から受け取った文字列を保持して永久ループ。引数として与えられたパスに名前付きパイプと、自身の PID を含むファイルを作成する。
  • SIGUSR1 か SIGUSR2 のシグナルを受け取ると、名前付きパイプに文字列を出力する。

外部からは吐き出された PID 情報をもとにシグナルを飛ばし、 cat <名前付きパイプ で値を受け取ります。

シンプルに仕上がっているのですが…、結果はいまいち。

永久ループに含まれる sleep 1 の影響を受けてか、シグナルを受けても即座に出力を返してくれないようです。ディスクへの負荷は抑えられる可能性はありますが、どうも求めているものとは違います。

そもそも、よくよく考えてみれば大規模なキューをメモリ上に抱えるのは、大抵のケースで領域の無駄遣いです。

やってから

学んだつもりでいることと、思ったこと。羅列。

  • sleep 入りの永久ループとシグナルを使ったプロセス間通信を利用した擬似デーモンは、メモリに値を保持したまま処理を持続できるが、シェルスクリプトで実現した場合とくに速度は期待できない。
  • デーモン側で sleep ではなく名前付きパイプで待ち受けるようにすると高速に動くかもしれない。
  • 今回、名前付きパイプを初めて使用した。 GO 言語のゴルーチンみたいなことができそう。

やってから 2

記事投稿後、名前付きパイプで待ち受けるように実装すると即座に値を返してくれるようになりました。

mem-echo

同じリポジトリですが、リンク先が違います。以前のものを別ブランチとして切り、こちらをマスターにしました。

続いて、学んだつもりでいることの追記。

  • sleep の影響範囲は思っていたよりもでかい。シグナルで割り込まれようが眠り続ける。
  • もしかすると、全ての処理が sleep の終了を待つのではなく出力処理については眠りが解けるまでやらないってことかもしれない。けど、検証はもう眠いのでまたいずれ気が向いたらということで、 sleep 22222

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です