Pythonでのスレッドの使い方(サンプルソース)

2010年2月14日

Posix準拠のプラットフォームではpthreadがサポートされています。 Pythonのスレッドはこのpthreadを使っているので、pthread環境下では ネイティブスレッドを使用できます。当然Linux系の環境ならば使用可能です。


Pythonでのスレッド実装方針は大きく2つあります。
一つはthreading.Threadクラスをオーバーライドしてスレッド本体の実装を実現する方法で、 もう一つはスレッド実行したい関数をコールバック登録する方法です。
より原始的なクラスthreadもありますが、threadingクラスがほとんど全ての機能を 内包しているのでこちらがお勧めです。

(注)threadクラスを使うメリットの一つとしては、明示的にスレッド処理を停止する exit()メソッドが提供されている点にありますが、あまりスレッドの原理を知らない人が スレッドを任意のタイミングで停止するのは危険です。 


コールバック登録する方法は簡単です。例えば以下のソースを参考にしてください。

1
2
3
4
5
6
import threading

def hello(pstr):
    print pstr

threading.Thread(target=hello, args=("world",)).run()

上記実装方法だとrun()メソッドを直接呼んでいるので 関数呼び出し的な動き(つまりスレッドじゃない)になるので間違いです。 

threadingクラスではstart()メソッドが提供されています。これは別スレッドを生成しrun()を実行してくれるクラスです。threadingクラスをオーバーライドした実装例を以下に示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/python
# -*- encoding: utf-8 -*-
# coding: utf-8
import sys, time
import threading
class Child_t(threading.Thread):
    __num_of_cnts = 0
    __thrd = None
    def __init__(self, num_of_cnts):
        threading.Thread.__init__(self)
        self.__num_of_cnts = num_of_cnts
        self.__thrd = self.getName()

    def run(self):
        print "[%s] enter" % self.__thrd
        cnt = 0
        while ( cnt < self.__num_of_cnts ):
            cnt += 1
            print "[%s] child!" % self.__thrd
            time.sleep(0.01)


def main():
    thrdid = threading.currentThread().getName()
    num_of_prints = 30
    child_t = Child_t(num_of_prints)
    child_t.start()
    cnt = 0
    while ( cnt < num_of_prints ):
        cnt += 1
        print "[%s] parent!" % thrdid
        time.sleep(0.01)
        child_t.join()
        print "[%s] END" % thrdid


if __name__ == "__main__":
        main()

サンプルソースで使用している各メソッドの使用については、 Threadクラスマニュアルを 参照してください。

上記start()メソッドでスレッドをアクティブにします。注意点としては、start()した直後に 処理が遷移する保証はないということです。あくまでOSのスケジューラの選択対象となっただけに過ぎず、 いつCPUリソースがchild_tスレッドにスイッチするかはスケジューラ次第です。また、間違っても run()メソッドを呼び出さないようにしましょう。関数呼び出し的な処理の振る舞いになってしまいます。
最後にjoin()で親スレッドが子スレッドchild_tの終了を待ちます。 子スレッドが終了したら、親スレッドの処理を停止するようにしています。