Why does this multithreaded Python program print correctly from 0 to 99?
This is the code
from Queue import Queue from threading import * threadLock = Lock() def do_stuff(q): while True: threadLock.acquire() print q.get() q.task_done() threadLock.release() q = Queue(maxsize=0) num_threads = 10 for x in range(100): q.put(x) for i in range(num_threads): worker = Thread(target=do_stuff,args=(q,)) worker.setDaemon(False) worker.start() q.join()
When I execute this code, I get a perfect order of numbers printed from 0 to 99 When I delete do_ When locking in stuff, I want the numbers from 0 to 99 to print unsorted, but even if there are some wrong numbers here and there, it mainly prints the range of reordering from 0 to 99 Why? Shouldn't it be unclassified because I don't synchronize threads in any way?
Solution
Your function does nothing else between retrieving the next number from the queue and printing it
Python holds a lock (GIL) when executing each bytecode, so thread switching can only be performed between bytecodes The viewing function (no lock) shows us that there is only one position. Thread switching will make another thread grasp the next number and print it before the previous thread can print them:
>>> import dis >>> def do_stuff(q): ... while True: ... print q.get() ... q.task_done() ... >>> dis.dis(do_stuff) 2 0 SETUP_LOOP 31 (to 34) >> 3 LOAD_GLOBAL 0 (True) 6 POP_JUMP_IF_FALSE 33 3 9 LOAD_FAST 0 (q) 12 LOAD_ATTR 1 (get) 15 CALL_FUNCTION 0 18 PRINT_ITEM 19 PRINT_NEWLINE 4 20 LOAD_FAST 0 (q) 23 LOAD_ATTR 2 (task_done) 26 CALL_FUNCTION 0 29 POP_TOP 30 JUMP_ABSOLUTE 3 >> 33 POP_BLOCK >> 34 LOAD_CONST 0 (None) 37 RETURN_VALUE
Even if the thread switches there, another thread must complete the call before the control switches back_ Function and print_ Item bytecode so that you can see the items printed in order
Thread switching must be in call_ Function and print_ Between items If you introduce more instructions there, you will increase the chance of printing numbers out of order