[Python-ml-jp 3754] Re: python での co-operative multi thread programming

kenji kenji @ nasuinfo.or.jp
2006年 10月 13日 (金) 12:37:40 JST


小林@那須です。返答ありがとうございます。

>本当にpre-emptiveかどうかは下層のスレッドライブラリに依存す
>るんじゃないでしょうか。

Python は pre emptive な thread の実装だと勝手に断定していました。付
録 1 のコードを実行してみて、 test and set の狭間でのデータ化けが発生
したことだけで pre-emptive だと判断してしまいました。でも 
pre-emptive な thread は優先する thead の実行要求のために優先されない
 thead の実行が中断されるものです。この意味で python は pre-emptive 
な thread ではないですね。


もう少し調べ/考えてみると python での thread 実装は

・スレッドを生成するときスタック・フレームを割り当て
・Python マシン・コード 100 命令ごとにコンテキスト・スイッチ すなわち 
 プログラム・カウンタとスタック・フレームを切り替え
・スレッド間の調整として Lock が実装してある。Lock に失敗中のスレッド
 はコンテキスト・スイッチの対象にしない

を行っているだけだと解ります。タイム・スライスに近いしろものです。
Pre-emptive/co-operative を論ずるしろものではありませんでした。優先的
な処理を thead に行わせるために thread and safe の狭間でのデータ化け
が発生しているのではありません。100 instruction slice という単純な切
り替えのために thread and safe の狭間でのデータ化け発生しただけでした。


python thread の根本的な問題は

・既存モジュールの thread safe 性について感知しない

ことでしょう。極端な例として time.sleep(.) をあげます。マルチスレッド 
で CPU 時間負荷を分散するために必要な timer.sleep(.) 関数についてさえ、
python の仕様としては thread safe を保証していません。また 
timer.sleep(.) 関数の中で、それを呼び出した thead の lock を解除して
くれることも期待できないでしょう。これでは python で multi thread 
programming するなと言っているに等しいと思います。


>「スレッドは体に良くない。非同期にしなさい。コールバックしなさい」の
>Twisted 教に入信するといテもあるし。

と書いてくれたのが不思議でした。C プログラムでこんなことを言ったとし
たら馬鹿げています。でも上のことを考えると python でならば納得できま
す。

現状の python で thread safe を保証したいならば stackless python を使
うしかないのでしょう。

皆様の御指摘で python thread について理解を深められました。ありがとう
ございました。
================ kVerifierLab =====================
小林憲次
http://www.nasuinfo.or.jp/FreeSpace/kenji/index.htm
===================================================

----------------- 付録 ---------------------
//@@
# -*- coding: shift_jis -*-
# Thread test
import threading
import time

inGlb=0
class MyTask(threading.Thread) :
    def run(self) :
        #for i in range(0, 2000) :  # assert エラーにならないことのほうが多い
        for i in range(0, 8000) :   # assert エラーになったり、ならなかったり
        #for i in range(0, 20000) : # assert エラーに確実になる
            global inGlb
            if inGlb == 1:
                inGlb -= 1
            elif inGlb == 0:
                inGlb += 1
            else:
                print "assert error:", i
                assert(False)
            # print i/o 命令を実行させると、そこでコンテキスト・スイッチなりエラーにならないかと思ったが
            # assert エラーが発生する
            print "i:", i
            #time.sleep(0.01)

task1 = MyTask()
task2 = MyTask()
task1.start()
task2.start()

for n in range(20):
    time.sleep(0.1)
    print "main:", n
print 'end'
//@@@
//copy \#####.### temp.py /y




Python-ml-jp メーリングリストの案内