イベント駆動の世界観です。並列処理も参照のこと。
イベント駆動とは、「外部の環境から何らかのイベントが伝えられて、そのイベントに応答する形でプログラムを書く」こと。
Linuxカーネルのように、全てのプログラムのベースとなる環境的なプログラムや、Windows APIのように外部のメッセージの通信によって、ユーザーのハードウェア操作や中心となるウィンドウシステムの命令に応答するプログラムでは、形こそ違えど、このイベント駆動と呼ばれる制御モデルを設計の中心としている。
Linuxカーネルは、自分から何もしないプログラムで、ソフトウェアのシステムコール呼び出しやハードウェアの割り込みに対して、応答することでしか処理が行われない。これはNginxのようなサーバーデーモンや、コマンドラインシェルやインタープリタなどにも似ているスタイルである。
また、GUIのウィンドウアプリケーションでは、一言にイベント駆動といっても、何種類かのやり方の違いがある。ひとつは、XlibやWindows APIやSwingのリスナのように、イベントが常に送られてきて、次のイベントが送られてくる間隔をループし、メッセージループでそのイベントメッセージを処理するという方式。もうひとつは、そうしたメッセージループをフレームワークが行い、ユーザーはイベントハンドラやコールバック関数をウィジェットに登録し、自動的にメッセージがやり取りされるようにする方式(これを指してイベント駆動とかイベントドリブンと呼ぶこともある)。他にも、MFCのようにメッセージマップに対応するクラスライブラリのメソッドを継承・オーバーライドする方式などがある。
イベント駆動のプログラムは、えてして巨大化しやすい。巨大化すると小さな環境で動かないこともあり、開発の困難さも増え、軽量さやパフォーマンスも落ちる。特に、これがマイクロカーネルなどといったさらに高度なプログラムになると、開発が破綻してしまう。Linuxカーネルでは、モジュールを実行時に動的に追加・削除できるようなモジュラー化のスタイルを取りながら、不要な機能は必要に応じて削除できるようにし、マイクロカーネルではなくモノリシックカーネルの方式をとることで、開発を単純にし、パフォーマンスを向上させている。
こうした「イベント駆動」については、長い間コマンドラインインターフェースを取ってきたUNIXよりも、Windowsに軍配が上がる。
UNIXでは、X11を使う場合であってもコマンド操作が中心となるため、「万人が操作しやすいGUIインターフェースを作る」ということがおろそかになってきた。それはコマンドラインの優れた機能、grep/sed/awkやコマンドのオプションやシェルスクリプトなどを使いこなすことで、簡単に自動で処理を行うことができる、というメリットが、逆に初心者や一般ユーザー向けのことを考えてこなかったということの結果である。
アラン・ケイのダイナブック構想からMacintoshやWindowsに繋がる、「GUIによる仕事用のインターフェース」というモデルは、そもそもUNIXは取ってこなかった。逆に、Windowsにおいては、多くのプログラムが単純な「マウスやキーボードへの応答」となってしまい、グラフィックスやインタラクティブな操作による直感性と使いやすさはあるものの、バッチ処理による自動化やスクリプティングのことは考えられていない。多くの場合スクリプトは記述できず、手作業で操作を行わなければファイルやテキストの編集はできない。アプリケーションの機能や重さも大きく肥大化する傾向にあり、不正終了やフリーズも多い。また、ひとつのアプリケーションがシンプルなスタイルをとっておらず、複雑怪奇であるため、バグも多く、開発も困難を極める。(だが、Windowsについて言えばインターネット上のフリーソフトは豊富に存在し、テキスト処理を行うのであれば、サクラエディタなどのサードパーティのフリーソフトを使うことで何とかできる場合もある。)
UNIXのコマンドラインプログラムであれば、単純なプログラムとなり、枯れた技術でもあるためバグの入り込む余地が少なく、ひとつの「カーネル」の上で小さなプログラムが動くというシンプルなスタイルから安定しており、信頼性が高い。そのため、データベースやネットワークサーバーなどの高信頼性や高いスループレットが必要な処理では、UNIXのようなコマンドラインのOSが今でも使われるのである。
ある意味、Windowsは「仕事用で使う真面目な目的のためのゲーム」のようなものであると考えられる。ディスプレイに表示されるウィンドウと、マウスやキーボードによるイベント駆動が、ゲームのコントローラと似ているからである。逆に、UNIXは計算処理をたくさんさせるための「昔ながらのバッチ処理インターフェース」であると考えられる。Windowsは使っていて面白いが、UNIXは目的がなければ何の面白さもないだろう。
また、最近はLinuxにおいても、Windowsと同様のGNOMEやKDEのようなGUI環境が増えてきた。確かにWindows並みに使えるものにはなっているが、僕はこれらについてはまだまだであると思う。Windowsと似通った独自性のないインターフェースになっているし、Windowsと同程度にバグが多く、また解決が難しい不具合が多くみられ(特に日本語環境)、情報にありつける頻度は極端に少ない。こうした分野でWindowsと同じものを目指してはいるものの、まだまだ未完成品であると評価せざるを得ない。だが、一部のマニアックなオタクにおいては、Windowsとは違う「オープンソースなLinuxデスクトップ」として崇拝されており、それが悪いことであるとは思わない。逆に、GNOMEやKDEでも、ターミナルエミュレータを使うことはほぼ必須であり、またWindowsとは違って多くのオープンソースソフトウェアが無料でついてくるため、優れた素敵な環境にはなっている。カスタマイズ性も高い。開発環境やUNIXの練習環境、あるいはただの遊び用途であれば、お金を一銭も払わずに導入でき、「みんなでインターネット上で開発していて、自分も参加したい」という、研究・教育用途にはうってつけである。逆に言えば、研究・教育用途以外に、使い道はないだろう。
状態遷移とは制御モデルのひとつで、システムの状態を表すデータを保持しておいて、その状態データがどのように変わるかによって、実行の制御が変わってくるというモデル。
僕の作ったロボットなんかがいい例かもしれない。
状態遷移によるシステムは、「状態マシン」(オートマトン)としてモデル化が行われる。
状態も参照のこと。
(Code Reading ~オープンソースから学ぶソフトウェア開発技法~ (プレミアムブックス版)を参考にして執筆しました。)
セルオートマトンとは、要素の状態が隣り合う別の要素へと影響するようなシミュレーションモデルのこと。
もともとは生物の細胞分裂をシミュレーションするために用いられた。
(放送大学「コンピュータとソフトウェア ('18)」を参考に執筆しました。)
2023.04.14
GUI開発を参照のこと。
Windows APIを参照のこと。
Swingを参照のこと。
C#やVisual BasicやVisual Basic(フォームデザイナー)を参照のこと。
X11設定とプログラミングやGTKを参照のこと。
状態も参照のこと。
僕は、単純にprint()やinput()で入出力を行うプログラムは、プログラムのモデルとして単純すぎるのではないかと思う。
たとえば、機能を有効化・無効化し、ループするプログラムは考えられないだろうか。
このプログラムは、たとえばリンゴを木から落とし続ける猿のように、何も設定しなければ同じことを永遠に繰り返すが、さまざまなタイミングで機能を有効化・無効化することで、その動きを変えることができる。
なので、猿に対して「リンゴを落とせ」という命令を有効化するとリンゴを落とし続けるが、この命令を無効化し、「ブドウを落とせ」という命令を有効化すると、今度はブドウを落とし続ける。
これは、ある意味、AI的なところがあると思う。AIのようなプログラムを書く上で、このようなプログラムは単にprint()やinput()を命令通りに行うよりも、高度であるように思う。
実際のところ、並列処理を実現する上で、イベントループの方法を取るか、それともマルチスレッドの方法を取るかは重要な問題です。
たとえば、ApacheのようなWebサーバーは、マルチスレッドやプロセスを使った並列処理を行いますが、プロセスが一万を超えたぐらいから不安定になることが知られています。
これに対して、NginxやNode.jsでは、プロセスやスレッドはひとつのまま、接続ごとにイベントループを行うことで、この問題を解決し、軽量かつ少ないメモリで動くサーバーを実現しています。
つまり、Webサーバーにおいては、マルチスレッドを用いた並列処理よりも、イベントループのほうが優れているということを意味しています。
ほかの分野についてはどうでしょうか。Linuxカーネルは、マルチプロセスと仮想アドレス空間によるマルチタスクを行いますが、同時にシステムコールによるイベント駆動を行います。また、Windows APIでは、コールバック関数の呼び出しと同時にメッセージループを行います。
つまり、イベントループと並列処理は、「どちらも一緒に現れる」ようなモデルです。多くが、「イベント駆動をしながら並列処理をしている」と言えます。なので、どちらがどちらに対して優越しているものではないのかもしれません。