WSGIServerを3行でマルチスレッド化する
WSGIとは
PythonでWebアプリを作るときに必ず出てくる単語にWSGIがあります。 WSGIとは、Web Server Gateway Interface の略で、WebサーバーとPython製Webアプリを つなげる標準インタフェースです。
WSGIの上で動くようにアプリケーションを作ると、そのアプリケーションは修正無しに Apache+mod_wsgi, Apache+mod_python, fastcgi, scgi, cgi, 等の環境で動かせるように なります。
他にもミドルウェアという考え方があります。例えばOpenID認証機能をWebフレームワークの プラグインとして開発した場合では他のWebフレームワークでは利用できないのですが、 WSGIミドルウェアとして開発すればWebフレームワークを問わずに利用できるようになります。
標準ライブラリのwsgirefモジュール
Python2.5から、標準ライブラリにwsgirefモジュールが追加されました。その中にはWSGIサーバーも 入っているので、自分で書いたWSGIアプリを手軽に立ち上げたいときに重宝します。
次のコードは、簡単なWSGIサーバー+アプリの例です。
from wsgiref.simple_server import * def myapp(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['hello'] server = make_server('0.0.0.0', 8000, myapp) server.serve_forever()
WSGIServerのマルチスレッド化
上記のコードで立ち上がるWebサーバーは、シングルスレッド&シングルプロセスで動作しているので、 複数のクライアントからアクセスされた場合に問題があります。接続が遅かったり不安定だったりする クライアントが一つでも合った場合、その接続が完了するか切断するまで他の接続ができないので、 接続に失敗したり数十秒かかったりすることになります。
普通はWebアプリを公開する場合には標準ライブラリのWSGIServerではなくて別のサーバーを使う ものですが、お手軽な方法として3行追加と1行修正のみで、他のライブラリ無しに マルチスレッド化したりマルチプロセス化することが出来ます。 次のコードが上記のコードをマルチスレッド化したものになります。
from wsgiref.simple_server import * from SocketServer import * class ThreadingWsgiServer(ThreadingMixIn, WSGIServer): pass def myapp(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['hello'] server = make_server('0.0.0.0', 8000, myapp, ThreadingWsgiServer) server.serve_forever()
このコードについて簡単に説明します。 wsgiref.simple_server.make_server は第三引数でサーバークラスを指定することができて、 デフォルト値は wsgiref.simple_server.WSGIServer になっています。 WSGIServerの継承関係は次のようになっています。
SocketServer.BaseServer ↑ SocketServer.TCPServer ↑ BaseHTTPServer.HTTPServer ↑ wsgiref.simple_server.WSGIServer
SocketServerモジュールには、ThreadingMixIn, ForkingMixIn というクラスがあり、 SocketServer.BaseServer を継承したサーバークラスであれば簡単にマルチスレッド化 したりfork化したりできるようになっています。 WSGIServer も BaseServer を継承しているので、ThreadingMixIn/ForkingMixIn クラスを Mix-in してやるだけでマルチスレッド化やマルチプロセス化が可能です。
小さなテクニックですが、Webアプリが完成するまではサーバーの設定の問題とアプリの 問題が混ざらないようにしたいときとか、Webサーバーの設定ファイルを書くのに慣れてなくて 後回しにしたいときに重宝します。
ちなみに、 flup というライブラリには、 thread pool や prefork を使ったWSGIサーバーがあって十分実用になる速度が出るので、 標準ライブラリのサーバーだと遅いという時に利用できます。