同期と非同期について考えてみた

概念

絵でイメージすると、以前、
初期化パラメータ filesystemio_options の値によってI/Oに関するシステムコールがどのように変化するか - ablog
に書いた

みたいな感じ。

コマンドでイメージするなら、こんな感じでしょうか。
シェルでジョブをバックグラウンドで実行するのも非同期です。何らかの処理を実行しながら、他の処理を実行することができます。

% find . -name hoge.txt > hoge.log & # find を実行しつつ
% pwd # 他のコマンドを実行することができる
% jobs -l # 実行状況を確認してみて、終わってるなー
% cat hoge.log # find の実行結果を見てみよ

わからないことを誰かに聞くときに、答えてもらえるまでじーっと待っているのが同期、「わかったら教えてー」とお願いして、その間他のことをするのが非同期。つまり、非同期は本質的は並列ではないかと思います。

例をいくつかあげてみます。

  • AjaxだとWebページを読みながら、Webページ中の一部分だけ更新したりので、「読む」のと「情報の更新」を並列処理できます。
  • 電話だとつながるまで待って、相手に用件を伝えるので、その間に他のことをすることはできませんが、手紙やメールだと送るだけ送っておいて、他のことをできるので、これも並列処理できます。
  • 非同期I/Oでは非同期にI/O要求を並列で投げて、後で全てのI/Oが完了しているか確認したりします。
  • Oracle Databse で insert や update などの DML を発行すると、物理的にディスクに書き込む前にクライアントに返ってきますが(非同期)、commit を発行すると、ディスク上のREDOログに物理的に書込みが完了してから返ってきます(同期)。*1

ここ最近、「非同期」というキーワードをよく見かける気がしますが、並列処理の手段としての非同期が多いと思います。大規模Webサービスなど並列処理が必要とされるを行うシステムが増えていたり、CPUのクロック周波数の頭打ちによるメニーコア化しているという背景があり、非同期が流行っているのではないかと思います。

あと、メールやMQのような非同期の仕組みは投げとけば後はよろしくやってくれるので楽ですね。

具体例

  • メール
  • 手紙
  • 為替
  • 留守電
  • Ajax
  • node.js
  • Tatsumaki(Perl)、Tornado(Python)、EventMachine(Ruby)
  • 非同期I/O
  • メッセージキュー
  • キャッシュ

メリット/デメリット/注意点

同期
  • メリット
    • 仕組みみがシンプルなため、作りやすく運用も簡単。
  • デメリット
    • 並列化による性能向上のメリットを享受できない。
非同期
  • メリット
    • 同じ時間で処理できる仕事量が増え性能が向上する
  • デメリット
    • 分岐点や合流点を考慮する必要があり、仕組みが複雑になるため、作るのも運用するのも直列処理に比べると難しい。アーキテクチャをよく考えて作ったり運用したりしないと、トラブルやボトルネックが発生しやすい。

蛇足

非同期I/OはI/Oの並列化の手段として使われています。非同期でI/O要求を発行して並列処理を行いますが、RDBMSだと各I/Oが完了していることを確認します。Linux で libaio を使った場合の話ですが、io_submit(2) で I/O要求を発行して、io_getevents(2) で書込みを完了します。つまり、RDBMSは非同期I/Oを使って、並列で同期なI/Oを実現していると言えます。

*1:ストレージのキャッシュを使っている場合、Oracle Database からは物理的にディスクに書いたつもりでも、ストレージ内部では書かれていなかったりしますが、ここではそのあたりの説明は省略します。