4

私はしばらくの間Pythonを使用してきましたが、今日までPythonで同時実行を行ったことはありません。私はこのブログ投稿に出くわし、同様の(しかしより単純な)例を作成することにしました。

import os
import threading
import Queue

class Worker(threading.Thread):
    def __init__(self, queue, num):
        threading.Thread.__init__(self)
        self.queue = queue
        self.num = num

    def run(self):
        while True:
            text = self.queue.get()
            #print "{} :: {}".format(self.num, text)
            print "%s :: %s" % (self.num, text)
            self.queue.task_done()

nonsense = ["BLUBTOR", "more nonsense", "cookies taste good", "what is?!"]
queue = Queue.Queue()

for i in xrange(4):
    # Give the worker the queue and also its "number"
    t = Worker(queue, i)
    t.setDaemon(True)
    t.start()

for gibberish in nonsense:
    queue.put(gibberish)

queue.join()

うまくいくようですが、プリントに問題があり、理解できないようです。いくつかのテスト実行:

chris@DPC3:~/code/pythonthreading$ python owntest.py 
0 :: BLUBTOR
 1 :: more nonsense
3 :: cookies taste good
 2 :: what is?!
chris@DPC3:~/code/pythonthreading$ python owntest.py 
0 :: BLUBTOR
2 :: more nonsense
3 :: cookies taste good0 :: what is?!

chris@DPC3:~/code/pythonthreading$ python owntest.py 
2 :: BLUBTOR
 3 :: more nonsense1 :: cookies taste good

 2 :: what is?!
chris@DPC3:~/code/pythonthreading$

出力がこれほど奇妙にフォーマットされているのはなぜですか?

4

2 に答える 2

6

印刷はスレッドセーフではありません。

一部の文字がstdout1つのスレッドによってストリームにコピーされている間、別のスレッドもスケジュールされ、これ印刷され、文字をstdoutストリームにコピーします。

その結果stdout、呼び出しの目立たない結果は含まれていませんがprint、異なるスレッドからの混合出力がすべて混ざり合っています。

回避策は、sys.stdout.write()代わりに使用することです。これアトミック(スレッドセーフ)操作です。\n明示的な改行を含めるようにしてください。

于 2013-01-06T10:47:25.947 に答える
6

printアトミックではありません。

次の行:

        print "%s :: %s" % (self.num, text)

次のバイトコードに変換されます。

         24 LOAD_CONST               1 ('%s :: %s')
         27 LOAD_FAST                0 (self)
         30 LOAD_ATTR                3 (num)
         33 LOAD_FAST                1 (text)
         36 BUILD_TUPLE              2
         39 BINARY_MODULO       
         40 PRINT_ITEM          
         41 PRINT_NEWLINE       

ご覧のとおり、そこには2つの印刷バイトコード(PRINT_ITEMPRINT_NEWLINE)があります。スレッドが2つの間でプリエンプトされると、表示されている内容が表示されます。

sys.stdout.write()私は、次の理由から、このユースケースに対してより安全な賭けである他の人に同意します。

  1. 文字列を書き込む前に文字列全体をフォーマットする必要がありprintます(誤って使用print a, b, c,して、1つではなく3つの別々の書き込みになってしまう可能性があります)。
  2. これは、ソフトスペースと自動改行の問題を回避します。これらは両方ともprint、プログラムの他の部分のステートメントと相互作用する可能性があります。
于 2013-01-06T10:51:41.943 に答える