这是代码.
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和PRINT_ITEM字节码,以便您看到按顺序打印的项目.
线程切换必须在CALL_FUNCTION和PRINT_ITEM之间进行.如果您在那里引入了更多说明,则会增加无序打印数字的机会.