自己紹介

太田一樹。
東京の大学の情報科学科に通う大学生。moratorium満喫中。

お勧め書籍 [全部見る]

飾り

Search


Category Archives

Recent Entries

  1. 論文
  2. JJUG CCCでプレゼンします
  3. kzk's bookshelf
  4. En Google by Gulfweed
  5. PNUTS
  6. コメントスパム対策
  7. Hadoop + Luceneで分散インデクシング
  8. Hadoopの解析資料
  9. Cluster 2008
  10. SWoPP 2008

2006年12月06日

PythonでMultiThreadServer

文字列処理を頻繁に行う+OSネイティブのマルチスレッドを使いたいという要求から、Pythonをいじってみました。題材としてはThread Pooling型のMultiThreadServerです。

大体以下のような感じになりました。


import sys
import os
from threading import *
from socket import *
from signal import *

class PyWorkerThread(Thread):
    def __init__(self, server_sock, accept_mutex, process_func):
        self.server_sock  = server_sock
        self.accept_mutex = accept_mutex
        self.process_func = process_func
        return

    def run(self):
        server_sock  = self.server_sock
        accept_mutex = self.accept_mutex
        process_func = self.process_func
        while 1:
            accept_mutex.acquire()
            (sock, fromaddr) = server_sock.accept()
            accept_mutex.release()
            sock.settimeout(30)
            process_func(sock)
            sock.close()
        return

class PyMultiThreadServer:
    def __init__(self, port):
        signal(SIGPIPE, SIG_IGN)
        self.sock = self.createServerSock(port)
        self.threads = []
        self.accept_mutex = Lock()
        for i in range(0, 20):
            th = PyWorkerThread(self.sock, self.accept_mutex, self.process)
            self.threads.append(th)
        return

    def start(self):
        for th in self.threads:
            th.start()
        for th in self.threads:
            th.join()
        return

    def createServerSock(self, port):
        sock = socket(AF_INET, SOCK_STREAM)
        sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        sock.bind((gethostname(), port))
        sock.listen(5)
        return sock

    def process(self, sock):
        sock.send("aiueo\n")
        return

if __name__ == "__main__":
    s = PyMultiThreadServer(40000)
    s.start()


PyWorkerThreadが個々のリクエストを裁くスレッドオブジェクトで、PyMultiThreadServerが複数個のPyWorkerThreadをPoolingしているサーバーです。はまった所としては、Thread.start()の代わりにThread.run()を使用してしまいThread切り替えが全く行われなかった点です。これはGoogle先生に助けてもらって解決しました。


PyMultiThreadServerを継承 & process関数を再実装して使います。「できたー」と喜んでいたらちゅんさんSocketServerというのが有るというのを知らされました。あらら。しかしこの辺がブラックボックス化されてるのは非常に気持ち悪いので自分のを使うことにします。


Rubyと比べると、classメンバにprivate等のアクセス権を指定できなかったり、selfが氾濫したり、アンダースコアが氾濫する点が気持ち悪いように感じます。しかしインデントが強制される事によって汚いコードが書けなくなるので(油断するとインデントが物凄く深くなって自ずと関数に分けたくなる)これはこれで良い気がします。


Thread pooling型のサーバーについていつも気になるのが、accept(2)をthread内で呼び出す際にaccept_mutexで保護する必要が有るのかどうかという点です。全スレッドが一斉にaccept(2)しに行くとプログラム全体がブロックするのでmutexで囲むべしとRichard Stevens本(Unix Network Programming)に書いてあった気がするのですが、accept(2)自体がスレッドセーフという噂もあります...。誰か詳しい人がいたら是非教えて下さい...。


[参考]
Python at Google.notes


trackbacks

trackbackURL:

comments

comment form
comment form