这是代码。
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()
当我执行这段代码时,我得到了从 0 到 99 的打印完美排序的数字。当我移除 do_stuff 中的锁时,我希望从 0 到 99 的数字未排序地打印,但是即使这里和那里有一些错误的数字,它主要打印从 0 到 99 再次排序的范围。这是为什么?它不应该是未排序的,因为我没有以任何方式同步线程吗?
最佳答案
您的函数在从队列中检索下一个数字和打印它之间不会执行任何其他操作。
Python 在执行每个字节码时持有一个锁(GIL),因此只有在 个字节码之间线程可以切换。查看函数(没有锁)向我们展示了只有 一个 线程切换可以让另一个线程有机会获取下一个数字并在前一个线程可以打印它们之前打印它:
>>> 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
即使线程在那里切换,另一个线程也必须在控制切换回来之前完成CALL_FUNCTION
和字节码以查看乱序打印的项目。
线程切换必须发生在 CALL_FUNCTION
和 PRINT_ITEM
之间。如果您在此处引入更多指令,就会增加数字乱序打印的可能性。
关于python - 为什么这个多线程 python 程序可以正确打印 0 到 99?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24430008/