Twistedの概要
Twistedは,プログラミング言語Pythonで書かれたイベント駆動型ネットワークプログラミングのフレームワークです.公式サイト(http://twistedmatrix.org/)からMITライセンスで配布されています.
Twistedは,P2Pファイル配信アプリケーションのBitTorrentで利用されています.また,WebアプリケーションフレームワークZopeでは,HTTPサーバとしてオプションで利用可能です.AppleのiCalサーバではWebDAV機能がTwistedで構築されています.それ以外にもLinux仮想化技術のXenで,バーチャルマシンのモニタにも利用されるなど,多くのアプリケーションで利用され,実績もあるフレームワークです.
Twistedの特徴の1つは,複数のネットワークプロトコルを統一的に扱うことができることです.つまり,HTTPサーバとしての機能だけでなく,IMAPサーバやSMTPサーバなども同時に構築することができます.たとえば,blogでは,moblogのようにメールによるコンテンツの更新ができるものがあります.通常は,HTTPサーバとSMTPサーバ,POPサーバを別々に立ち上げ,POPサーバの監視プログラムを用意します.監視プログラムで定期的にPOPサーバにメールが届いていているか確認し,メールが届いている場合はデータベースを更新するような作業が必要になります.この場合,TwistedでHTTPサーバ,SMTPサーバを構築すると,メールが届いた直後にデータベースを更新することができます.ユーザには常に最新の情報をHTTPサーバから配信されるようになります.これらのサーバ群を1つのプロセスで実行することができるので,アプリケーションのセットアップや管理の繁雑さが軽減されます.
また,HTTPサーバやSMTPサーバなどのような高レベルなプロトコルだけではなく,TCPやUDP,マルチキャスト,UNIXソケットなど低レベルな処理も直接扱うことができます.
Twistedのインストール
最初にインストール方法について説明します.
Windowsへのインストール
Windowsへインストールする場合は,TwistedのWebサイトに用意されているバイナリインストーラを利用します.Windows用インストーラにはお使いのPythonのバージョンごとに用意されています.使用する環境に応じてダウンロードするバイナリを選択してください.
次にダウンロードしたインストーラを起動すると,図1のような画面が表示され,インストールが始まります.特に問題がない限りは,デフォルトのオプションでインストールを進めます.
Linuxへのインストール
パッケージからのインストール
筆者が愛用しているGentoo LinuxやUbuntuでは,ディストリビューションのパッケージ管理システムにTwistedのパッケージがすでに存在しています.
Gentoo Linuxではスーパーユーザになり,次のコマンドでビルド/インストールできます.
emerge -av dev-python/twisted
また,Gentoo Linuxでは,Twistedの各サブプロジェクトごとにebuildが分かれていますので,自分の使いたいサブプロジェクトを適宜インストールします.今回は,Twisted Webのサブプロジェクトも使用するので,twisted-webもインストールしています.
emerge -av dev-python/twisted-web
ソースコードからのインストール
ソースコードからインストールする場合は,TwistedのWebサイトからtarballをダウンロードして展開します.展開したディレクトリに移動してからビルド/インストールを行います.
$ wget http://tmrc.mit.edu/mirror/twisted/Twisted/2.4/Twisted-2.4.0.tar.bz2
$ tar jxvf Twisted-2.4.0.tar.bz2
$ cd Twsited-2.4.0
$ su -c "python setup.py install"
Twisted自体はピュアPythonですが,Twistedが依存しているZopeInterfaceパッケージ(注1)はgccによ
るコンパイルが必要です.
ZopeInterfaceはPythonのC拡張を利用せずに動作させることもできますが,実行時の動作が若干
遅くなります.特に理由がない限りはgccなどの開発環境をあらかじめ用意しておいてください.
注1) ダウンロードしたtarballに同梱されています.
動作確認
インストールが終了したら,Twistedの動作確認を行います.コンソールから次のコマンドを実行します.
# python
Python 2.4.3 (#1, Aug 9 2006, 17:43:28)
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import twisted.internet.reactor
>>> twisted.internet.reactor.run()
正常に起動できると,コンソールには何も表示されません.Ctrl+Dを押して終了するとコンソールは入力待ちの状態になります.もし,途中でエラーが出た場合は,インストール中にエラーが出ていないかを確認してください.
ネットワークプログラミング
プログラムには,処理が終了するまでに時間がかかるものがあります.時間がかかる処理は大きく分けて2種類あります.
- 結果を計算するまでにCPU時間を消費するもの
- データが利用できるようになるのを待つもの
ネットワークプログラミングでは,データを取得するのを待つ処理がほとんどです.たとえば,メール送信処理では,リモートにあるサーバに接続して,リモートのサーバがメールを処理できるようになるのを待ちます.リモートのサーバがメールを処理できるようになると,メールを実際に送信して送信確認を待ってから切断します.
これらの処理では長い待ち時間が発生します.送受信を行うための多くのライブラリ(注2)では,データを送信しようとしている間,処理を待ち続けなければなりません.つまり,同時に大量のデータを送受信する場合は効率的に処理を行うことができません.
効率的な処理を実現するためには,データの送受信を行っている間(送受信の待ち時間)に別の処理も継続して行うモデルが必要になってきます.
注2)Pythonの標準ライブラリも含みます.
効率的な処理を行う2つの方法
これを解決するようなネットワークプログラミングの方法は,次の2つが一般的です.
- ブロッキングIOを使ってコネクションごとにプロセスやスレッドを起動して処理を行う
- ノンブロッキングシステムコールを使って,すべてのコネクションを1つのスレッドで処理する
ブロッキングIO
1つ目のブロッキングIOは,send関数やrecv関数を使用してデータを送受信します.通常,これらの関数はデータを完全に送信/受信するまでブロックされ続けます.
GUIアプリケーションを作成する場合など,ユーザからの処理に応じてネットワークにアクセスする際に,ブロッキングIOで処理すると,ネットワークの遅延やサーバのレスポンスが悪い場合に,ユーザからの処理を受け付けることができなくなり,延々と待ち状態になる可能性があります.
このため,ネットワークに入出力を行う場合は,別にスレッドを動かして,処理を並行させる必要があります.ただし,マルチスレッドでアプリケーションを作成する場合は,スレッド間の同期の問題などが発生するので,細心の注意が必要になります.
ノンブロッキングシステムコール
Twistedでは,2つ目のノンブロッキングシステムコールを利用してこの問題に対処しています.ノンブロッキングシステムコールにより1つのスレッドで複数のコネクションを扱うことが可能です.
1つのスレッドで複数の接続を処理する場合,OSではなくアプリケーション側で処理をスケジューリングしなければいけません.通常,それぞれの接続が読み書き可能な状態になったときに,登録してあるコールバック関数をコールするようになっています.このしくみは,非同期プログラミングやイベント駆動型プログラミングと呼ばれています.
非同期プログラミングにおけるプロセス
非同期プログラミングでは,メールの送受信は次のようなプロセスになります.
- リモートサーバに接続するためのconnect関数をコールします
- connect関数はすぐに処理が戻ります
- 接続が確立すると通知を受け取ります
- 接続の通知を受け取るとメールを送信します
この一連の処理で,プログラムは接続が確立するのを待たずに別の処理(別のメールの送信など)を行うことができます.
非同期プログラミングでは,データを送受信可能になると,コールバック関数がコールされます.コールバック関数は,データを受信できるようになったときなどに,受信データを引数にとって,呼び出されます.
同期プログラミングでは,データをリクエストする関数は,データが受信できるまで待ち続けて,データを処理します.一方,非同期プログラミングでは,データが利用できるようになったときにコールバック関数が呼ばれて,コールバック関数の中で固有の処理を行います.
メリット/デメリット
ブロッキングIOで複数のソケットを扱う場合,効率的に動作させるためには,複数のスレッドを作成して処理を行うことが必要になります.ノンブロッキングIOでは,1つのスレッドで同時に複数のソケットを扱うことが可能です.そのため,送受信の待ちが多い処理を行う場合,効率的に動作させることができます.
ただし,1つのスレッドで動作させるため,ネットワークから受信したデータ自体の処理に多くの時間を消費すると,プロセス全体がブロックされます.そのため,ブロッキングIOより効率が下がり,ネットワークへの入出力に依存しない部分は別スレッドで動作させるなどの工夫が必要になります.ブロッキングIOとノンブロッキングIOの特性をふまえて,どちらの方式を採用するかを決定してください.
また,開発効率という側面から見ると,ブロッキングIOに対してノンブロッキングIOはプログラミングが難しいという点も理解しておいた方が良いでしょう.select/pollのAPIの使用方法が難しいということもありますが,それ以上に,ネットワークへの入出力における一連の処理がソースコード上に分散されてしまうことも原因の1つです.
Python標準ライブラリとの比較
Twistedフレームワークは,ノンブロッキングIOを使用して(非同期ネットワーク)プログラミングするためのライブラリです.同様の非同期プログラミングライブラリとしては,Pythonの標準ライブラリのasyncoreが有名です.
両者は似ていますが,全く別の問題を取り扱います.Twistedは巨大で複雑なライブラリで,多くのプロトコルとシステムをサポートしています.一方のasyncoreは,単純で小さなモジュールで,プログラミングに必要な最低限の機能だけを提供しています.また,一度に1つだけのプロトコルを扱うことにフォーカスしています.
TwistedのAPIレイヤ
Twistedは,非同期ネットワークプログラミングをするために,いくつかのレイヤに分けてAPIを提供しています.
最も低レベルなAPIは,TCPやUDPを非同期に扱うことができます.さらに高レベルなAPIでは,HTTPやSMTPなどのインターネットプロトコルを抽象化しています.
高レベルなAPIでは,大きなプロトコルを扱うため,Twistedから分離したサブプロジェクトとして提供されています.Twistedから正式に提供されているもの以外にも,自分でプロトコルを定義して新たに作成することができます.
表1にTwistedが提供しているサブプロジェクトを示します.表1を見てわかるように,Twistedは多くのインターネットプロトコルをサポートしています.また,サーバサイド,クライアントサイド両方のプロトコルをサポートしています.このことは,他のフレームワークにはない大きな特徴です.
| プロジェクト名 | 説明 |
| Twisted Conch | SSHとSFTPプロトコルのプロジェクトです. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted Web | HTTPバージョン1.0のプロトコルを実装しています. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted Web2 | HTTPバージョン1.1のプロトコルを実装しています. まだ実験的なプロジェクトです.
|
| Twisted Mail | SMTP,IMAP,POPプロトコルを実装しています. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted Names | DNSプロトコルを実装しています. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted News | NNTPプロトコルを実装しています. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted Words | AIMやMSN,IRCなどのチャットとインスタントメッセージの機能を実装しています. クライアントサイドとサーバサイドの両方を含んでいます.
|
| Twisted Trial | 標準ライブラリのunittestと互換性のある自動化されたテストフレームワークを実装しています. |
| Twisted Lore | ドキュメント作成のためのツールでHTMLやLaTeXなどに出力できます. |
| Twisted Runner | プロセス管理のためのライブラリです. inetdのようなサーバも含んでいます.
|