Python中的队列是如何工作的?

5
测试代码非常简单:
import threading, Queue
import time, random

class Worker(threading.Thread):
    def __init__(self, index, queue):
        threading.Thread.__init__(self)
        self.index = index
        self.queue = queue
    def run(self):
        while 1:
            time.sleep(random.random())
            item = self.queue.get()
            if item is None:
                break
            print "index:", self.index, "task", item, "finished"
            self.queue.task_done()

queue = Queue.Queue(0)
for i in range(2):
    Worker(i, queue).start()
for i in range(10):
    queue.put(i)
for i in range(2):
    queue.put(None)
print "Main OK"

每次运行结果都有些不同,这里只是其中一个例子:
Main OK
index: 1 task 0 finished
index: 0 task 1 finished
index: 0 task 2 finished
index: 1 task 3 finished
index: 1 task 4 finished
index: 0 task 5 finished
index: 1 task 6 finished
index: 0 task 7 finished
index: 1 task 8 finished
index: 1 task 9 finished

当主线程终止时,将打印“Main OK”,然后第一个线程将被执行,直到进入time.sleep(random.random()),然后第一个线程将休眠,第二个线程将继续执行。与第一个线程相同,第二个线程在运行到time.sleep(random.random())时也会休眠,然后第一个线程将再次继续。它将在Main OK之后立即打印index:0 task 0 finished,但实际上跟随Main OK的是index: 1...而不是index: 0...!为什么?并且似乎队列机制没有像正常的多线程一样运行,有时相同索引的线程将连续执行三次或更多次!队列机制是如何工作的?任何帮助都将不胜感激!


如果你不理解多线程,请不要进行多线程编程。 - Zoran Pavlovic
3个回答

4

线程的执行顺序没有保证。如果要有保证,需要进行大量的同步,这将导致性能串行化。

此外,应该使用 queue.join() 来等待(阻塞式)所有工人完成。


3
您有三个线程:两个工作线程和一个主线程。这三个线程同时运行,但您建议的(在预先知道的点处清除开关)并不正确。您需要在填充队列之前启动工作线程,以便它们立即进入睡眠状态。然后再填充队列。很可能其中一个线程会在另一个线程之前离开其睡眠状态,并获取队列中的第一项进行处理(打印),然后再次进入下一个睡眠状态。由于随机性,第一个工作线程每次睡眠0.01秒,而另一个工作线程从开始就睡眠0.4秒,因此可能所有项目都将由第一个线程处理。
如果有多个工作线程在Queue.get()方法中阻塞(只有在队列未填满时才会发生),则无法确定哪个工作线程会被唤醒来处理该项。
您的随机睡眠不够同步,不能在两个工作线程之间产生清晰的来回切换,因为一个线程可能会睡得太久,以至于另一个线程在同一时间内处理了两个项目。尝试使用以下内容始终在两个进程之间进行清晰的切换:
def run(self):
    if self.index == 0:
        time.sleep(0.1)
    while 1:
        time.sleep(0.2)
        item = self.queue.get()
        if item is None:
            break
        print "index:", self.index, "task", item, "finished"
        self.queue.task_done()

2

虽然线程运行的顺序不能保证,但您也在那里使用了time.sleep(random.random())

>>> random.random()
0.044693605707810558
>>> random.random()
0.16270424255105465
>>> random.random()
0.74068552817650446

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接