具有非空队列的Python Queue.get(block = False)。它可以提升Queue.empty吗?

时间:2022-12-07 21:04:10

I'm using python's Queue.Queue to synchronize several threads. First, a Queue is populated with N elements, as in

我正在使用python的Queue.Queue来同步几个线程。首先,队列中填充N个元素,如

N = 10
q = Queue.Queue()
for i in range(N):
  q.put(i)

Then, several threads consume the elements from the queue with block=False

然后,几个线程使用block = False从队列中使用元素

q.get(block=False)

My question is: can the previous call to Queue.get() raise Queue.Empty in any of the first N calls?

我的问题是:先前调用Queue.get()可以在前N个调用中的任何一个中引发Queue.Empty吗?

Thanks!

1 个解决方案

#1


The first N calls to get() will succeed; q.get(block=False) will only raise Queue.Empty if the queue is actually empty. All the calls to get made by your threads are synchronized, so the first N threads that get the mutex used by the Queue will successfully get an item from the Queue. If you have N+1 or more threads, any get beyond the Nth will raise Queue.Empty. This is fairly easy to see for yourself by looking at the relevant parts of the Queue code, as mentioned by Eric.

前N个调用get()将成功;如果队列实际为空,q.get(block = False)只会引发Queue.Empty。线程所做的所有调用都是同步的,因此获得Queue使用的互斥锁的前N个线程将成功从Queue获取一个项目。如果你有N + 1个或更多个线程,那么任何超过Nth的东西都会引发Queue.Empty。通过查看Eric提到的Queue代码的相关部分,可以很容易地看到这一点。

class Queue:
    """Create a queue object with a given maximum size.

    If maxsize is <= 0, the queue size is infinite.
    """
    def __init__(self, maxsize=0):
        self.maxsize = maxsize
        self._init(maxsize)
        self.mutex = _threading.Lock()
        self.not_empty = _threading.Condition(self.mutex)
        ... # Stuff we don't care about

    def get(self, block=True, timeout=None):
        self.not_empty.acquire() # Only on thread can hold this at a time
        try:
            if not block:
                if not self._qsize(): # If there's nothing in the Queue
                    raise Empty
            ... # Other stuff we don't care about, since you use block=False
            item = self._get()
            self.not_full.notify()
            return item
        finally:
            self.not_empty.release()

    def _init(self, maxsize):
        self.queue = deque()

    def _qsize(self, len=len):
        return len(self.queue)

#1


The first N calls to get() will succeed; q.get(block=False) will only raise Queue.Empty if the queue is actually empty. All the calls to get made by your threads are synchronized, so the first N threads that get the mutex used by the Queue will successfully get an item from the Queue. If you have N+1 or more threads, any get beyond the Nth will raise Queue.Empty. This is fairly easy to see for yourself by looking at the relevant parts of the Queue code, as mentioned by Eric.

前N个调用get()将成功;如果队列实际为空,q.get(block = False)只会引发Queue.Empty。线程所做的所有调用都是同步的,因此获得Queue使用的互斥锁的前N个线程将成功从Queue获取一个项目。如果你有N + 1个或更多个线程,那么任何超过Nth的东西都会引发Queue.Empty。通过查看Eric提到的Queue代码的相关部分,可以很容易地看到这一点。

class Queue:
    """Create a queue object with a given maximum size.

    If maxsize is <= 0, the queue size is infinite.
    """
    def __init__(self, maxsize=0):
        self.maxsize = maxsize
        self._init(maxsize)
        self.mutex = _threading.Lock()
        self.not_empty = _threading.Condition(self.mutex)
        ... # Stuff we don't care about

    def get(self, block=True, timeout=None):
        self.not_empty.acquire() # Only on thread can hold this at a time
        try:
            if not block:
                if not self._qsize(): # If there's nothing in the Queue
                    raise Empty
            ... # Other stuff we don't care about, since you use block=False
            item = self._get()
            self.not_full.notify()
            return item
        finally:
            self.not_empty.release()

    def _init(self, maxsize):
        self.queue = deque()

    def _qsize(self, len=len):
        return len(self.queue)