pythonでのスレッド

基本事項

  • pythonのthreadは複数コアに跨がらないので,CPU空き時間がないような並列化では意味が無い.そのような場合にはmultiprocessingモジュールを使う.
  • threadingモジュールを使って、threading.Threadのサブクラスを作るか、インスタンスを作る,の2つの方法がある.サブクラスでやる場合に,runに引数は渡せない(runはselfだけを取る).コンストラクタ(init)で渡しとく必要があることに注意する.
  • 処理はrunメソッドをオーバライドして、startメソッドで実行する。
  • 同期はjoinメソッド。
  • メインスレッド終了時にサブスレッドを終了するにはsetDaemon(True)にする。
  • 外からスレッドを止める(kill, stop)方法は無い(古いVersionには_stop()が隠しメソッドとしてあったが今は無い).そもそも外からいきなりスレッドをkillことは良くない.  方法としては,「ストップフラグをスレッドに持たせておいて,それを定期的に確認させる.ストップフラグは外部からいじれるようにしておく」.そして,外部からいじるためにthreading.Eventを使う.Eventはスレッドセーフな(複数のスレッドがアクセスしてもちゃんと同期をとってくれる)変数なのでこれをフラグとして使うんだ.
# Threadを継承したクラスを作成する場合
import threading
import time

class MyThread(threading.Thread):
    def __init__(self, i):
        super(MyThread, self).__init__()
        self.i = i
        self.stop_event = threading.Event()
        self.setDaemon(True)
        
    def stop(self):
        self.stop_event.set()

    def run(self):
        print 'START {}'.format(self.i)
        i = 0
        while not self.stop_event.is_set():
            print 'I am no. {}'.format(self.i)
            time.sleep(self.i)
            i += 1
        print 'END {}'.format(self.i)

if __name__ == '__main__':
    th1 = MyThread(1)
    th2 = MyThread(2)
    th1.start()
    th2.start()
    time.sleep(3)
    th1.stop()
    th2.stop()
  • 特定のメソッドをスレッド化したい場合には下記のようにインスタンスを作成する.引数としては,targetでスレッドを指定,nameでスレッド名,argsでメソッドの引数を渡す.
# メソッドをスレッドとして実行
import threading

def say_hello(situation, who):
   print "Good {} {} !".format(situation, who)

if __name__ == '__main__':
   th1 = threading.Thread(target=say_hello, name='morning_thread', args=('morning', 'Nobunaga'))
   th2 = threading.Thread(target=say_hello, name='eveningthread', args=('evening', 'Shingen'))
   th1.start()
   th2.start()