Why does the output of my Python program look like this (very weird)?

I have been working with Python for a while, but so far I have never done any concurrency. I came across this blog post and decided to make a similar (but simpler) example:

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() 

Everything seems to be working fine, but there seem to be some fingerprint issues that I cannot understand. Several test runs:

 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$ 

Why is the output file formatted this weird?

+4
source share
2 answers

print not atomic.

Next line:

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

translate to the following bytecodes:

  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 

As you can see, there are two print byte codes ( PRINT_ITEM and PRINT_NEWLINE ). If the flow is pushed between them, you will see what you see.

I agree with others that sys.stdout.write() is a safer bet for this use case, because:

  • it forces you to format the entire line before writing it (using print you can accidentally use print a, b, c, and eventually use three separate entries instead of one);
  • this wraps up the problems of softspace and automatic newlines, both of which can interact with print statements in other parts of the program.
+6
source

Printing is not thread safe.

While some characters are copied to the stdout stream by one stream, another stream is scheduled, which also prints, and it gets the opportunity to copy the characters to the stdout stream.

As a result, your stdout does not contain the hidden results of print calls, but mixed outputs from different threads, all mixed up.

In the process, sys.stdout.write() ; This is an atomic (thread safe) operation. Make sure you specify the explicit string \n .

+6
source

All Articles