【问题标题】:Why does the output of my Python program look this (very odd) way?为什么我的 Python 程序的输出看起来像这样(非常奇怪)?
【发布时间】:2013-01-06 10:20:11
【问题描述】:

我使用 Python 已经有一段时间了,但在今天之前我从未真正用它做过任何并发操作。我偶然发现了this blog post,并决定做一个类似(但更简单)的例子:

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$

为什么输出格式这么奇怪?

【问题讨论】:

  • 你可以改用sys.stdout.write(message) :)

标签: python multithreading output


【解决方案1】:

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       

如您所见,那里有两个打印字节码(PRINT_ITEMPRINT_NEWLINE)。如果线程在两者之间被抢占,您将看到您所看到的。

我同意其他人的观点,即 sys.stdout.write() 对于这个用例来说是一个更安全的选择,因为:

  1. 它会强制您在编写整个字符串之前对其进行格式化(使用print,您可能会不小心使用print a, b, c, 并最终得到三个单独的写入而不是一个);
  2. 它回避了软空格和自动换行的问题,这两者都可以与程序其他部分的print 语句交互。

【讨论】:

  • 这是非常有用的信息。手动制作换行符可以解决问题:print "{} :: {}\n".format(self.num, text),
【解决方案2】:

打印不是线程安全的。

当一些字符被一个线程复制到stdout 流时,另一个线程被调度打印,它将字符复制到stdout 流。

结果是您的stdout 不包含print 调用的谨慎结果,而是来自不同线程的混合输出,所有这些都混杂在一起。

解决方法是改用sys.stdout.write()一个原子(线程安全)操作。确保包含明确的 \n 换行符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    • 2020-02-21
    • 1970-01-01
    相关资源
    最近更新 更多