2009-11-08 22 views
11

私が作業しているPythonプロジェクトでスレッドを使用しようとしていますが、スレッドが自分のコードで動作しているように見えません。すべてのスレッドが順番に実行されているようです(つまり、スレッド1が終了した後にスレッド2が開始され、同時に開始されるわけではありません)。私はこれをテストするための簡単なスクリプトを書いており、それもスレッドを順番に実行します。Pythonスレッドでスレッドが順番に実行されているようです

import threading 

def something(): 
    for i in xrange(10): 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

は、ここで私はそれを実行しているから取得する出力です:

Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
world 
world 
world 
world 
world 
world 
world 
world 
world 
world 

同じ動作は、ループの繰り返しはるかに大きい数で観察されます。

ウェブと年老いたSOの回答を検索しようとしましたが、助けてくれたものが見つかりませんでした。 誰かがこのコードの何が間違っているかを指摘できますか?

答えて

13

現在、Pythonでは、指定された量のバイトコード命令を実行した後にスレッドが変更されます。彼らは同時に実行されません。それらのうちの1人がGIL(グローバルインタプリタロック)をリリースできるI/O集約型またはPythonに影響を及ぼさないモジュールを呼び出すときにスレッドを並列に実行するだけです。

は、私はあなたが単に二スレッドを生成することも、時間の「ロット」を取ることを忘れないでください10000のようなものにループ数をぶつけた場合、最大混合出力が得られますかなり確信しています。

+0

10000回の反復で同じ動作 – MAK

+0

私が取り組んでいる実際のプロジェクトでは、スレッドの1つはメッセージをリッスンし、コールバック関数を彼らが到着します。他のすべてのスレッドをブロックするだけです。残念ながら、実際のループコードは変更できません(スレッド内のクラスのrun()メソッドを呼び出すだけです)。 – MAK

+0

このようなスクリプトを実行すると、 './pythr.py |ユニーク-c'私は取得:8969こんにちは| 1ハローワールド| 6626世界| 1 | 3373世界| 1030こんにちは。だからそれはコントロールを変更します - それほど頻繁ではありません。 – viraptor

10

2番目のスレッドが開始されるまでに、最初のスレッドがループしてすでに印刷されています。

ここでは次のようになり、最初はいくつかのhelloを放出された後に開始第二のスレッドを見ることができます。

Hello 
Hello 
Hello 
Hello 
Hello 
Helloworld 

Helloworld 

Helloworld 

Helloworld 

Helloworld 

world 
world 
world 
world 
world 

Btw:あなたの例は意味がありません。 Threadsの唯一の理由はIOであり、IOは遅いです。あなたがIOをシミュレートするために、いくつかの睡眠を追加すると、それは期待通りに動作するはずです:

import threading 
from time import sleep 

def something(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

野生のミックスが表示されます:

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

worldHello 

Helloworld 
+2

forループの反復回数が大きくても少なくても、そのような出力は得られません。私のコンピュータでは、それは常に逐次的です。私はabyxが提案したように、これはOS /プロセッサに依存すると思います。 – MAK

+0

私は私の質問で言ったように、これは私の問題のための単なる例ではなく、私が働いているコード(はるかに大きいです)です。私の実際のコードでは、スレッドの1つがdbusシグナルをリッスンするループを実行します。 – MAK

3

これは本当にあなたのオペレーティングシステムのスケジューラ、お使いのプロセッサに依存します。それ以外
は、CPythonののスレッドが短いために、多くの時間がスレッドを順次実行し、またはその種の何かないことを意味し、GIL(PDF)、の完璧ではないことが知られています。

+2

あなたはおそらく、CPythonスレッドがGILに苦しんでいることを意味します... JythonにGILはありません。 – EOL

+0

@ EOL - あなたは正しいです、私は答えを更新しました – abyx

4

システムが単一プロセッサまたは複数のプロセッサを使用しているかどうかによって、動作が変わることがあります。これについては、David Beazleyのthis talkで説明されています。

viraptorが言うように、最初のスレッドがsys.getcheckinterval()バイトコード(デフォルトは100)を実行した後、GILを解放します。デビッド・ビーズリーの言うことを徹底的に要約すると、単一のプロセッサー・システム上で、2番目のスレッドは引き継ぐチャンスを持つことになります。しかし、マルチコアシステムでは、2つ目のスレッドが別のコアで動作している可能性があります。最初のスレッドはロックを再獲得しようとしますが、OSはプロセッサを切り替える時間がないため、おそらく成功します。これは、CPUバインドされたスレッドを持つマルチコアシステムでは、他のスレッドは決して見ていないかもしれないことを意味します。

way roundは、スリープステートメントを両方のループに追加して、 CPUにバインドされます。

関連する問題