python - 为什么这个多线程 python 程序可以正确打印 0 到 99?

标签 python multithreading python-2.7

这是代码。

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_FUNCTIONPRINT_ITEM 之间。如果您在此处引入更多指令,就会增加数字乱序打印的可能性。

关于python - 为什么这个多线程 python 程序可以正确打印 0 到 99?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24430008/

相关文章:

当提供从网络接收到的字符串时,Curses printw() 将仅打印换行符

python - 找不到文件错误 : [Errno 2] No such file or directory: 'ffprobe' : 'ffprobe'

python - 按 timedelta 修剪 TimeSeries

python - python 中的错误处理程序

javascript - 如何同步 JavaScript 回调?

c++ - 线程池理解问题

python - 将\n\t 等转义字符替换为\\t ,\\n

Python 共享值

python - random.randint 不生成随机值

python - 动态查找两个字符串之间的多个空格