伪造Python队列中的插入

时间:2013-06-07 21:55:49

标签: python multithreading

我在python中使用Queue,它的工作方式类似于频道。也就是说,无论何时进行插入,其他一些线程都在等待并获取插入的值。那么这个价值就是收益率。

@classsynchronized('mutex')
def send(self, message):

    # This might raise Full
    if not self._is_closed:
        self._queue.put(message)
        return True

    return False

@classsynchronized('mutex')
def close(self):

    # Don't do what we don't need to
    if self._is_closed:
        return

    # Make the _queue.get() request fail with an Empty exception
    # This will cause the channel to stop listenning to messages
    # First aquire the write lock, then notify the read lock and
    # finally release the write lock. This is equivalent to an
    # empty write, which will cause the Empty exception
    print("ACQUIRING not_full")
    self._queue.not_full.acquire()

    # Close first. If the queue is empty it will raise Empty as fast as
    # possible, instead of waiting for the timeout
    self._is_closed = True

    try:
        print("NOTIFYING not_empty")
        self._queue.not_empty.notify()
        print("NOTIFIED not_empty")
    finally:
        self._queue.not_full.release()
        print("RELEASED not_full")

def _yield_response(self):
    try:
        while True:

            # Fetch from the queue, wait until available, or a timeout
            timeout = self.get_timeout()
            print("[WAITING]")
            message = self._queue.get(True, timeout)
            print("[DONE WAITING] " + message)
            self._queue.task_done()

            # Don't yield messages on closed queues, flush instead
            # This prevents writting to a closed stream, but it's
            # up to the user to close the queue before closing the stream
            if not self._is_closed:
                yield message

            # The queue is closed, ignore all remaining messages
            # Allow subclasses to change the way ignored messages are handled
            else:
                self.handle_ignored(message)

    # This exception will be thrown when the channel is closed or
    # when it times out. Close the channel, in case a timeout caused
    # an exception
    except Empty:
        pass

    # Make sure the channel is closed, we can get here by timeout
    self.close()

    # Finally, empty the queue ignoring all remaining messages
    try:
        while True:
            message = self._queue.get_nowait()
            self.handle_ignored(message)

    except Empty:
        pass

我只包含相关方法,但请注意这是一个类。问题是,这不符合我的预期。队列确实关闭,所有打印都显示在控制台中,但是等待消息的线程没有被通知。相反,它总是以超时退出。

所有@classsynchronized('互斥')注释都使用相同的标识符(' mutex')进行类同步,即具有该注释的类中的每个方法相同的ID彼此同步。

我在关闭之前获取not_full锁的原因是为了防止在封闭的通道中插入。只有这样才能通知not_empty锁。

知道为什么这不起作用?还有其他建议吗?

提前致谢。

修改

我对打印件进行了一些更改。我创建频道并立即发送消息。然后我发送一个HTTP请求删除它。这是输出:

[WAITING]
[DONE WAITING] message
[WAITING]
ACQUIRING not_full
NOTIFYING not_empty
NOTIFIED not_empty
RELEASE not_full

所以:

  1. 第一条消息得到处理并成功发送(我在客户端获取,所以......)
  2. 然后队列正在等待。应该等待not_empty锁,对吧?
  3. 我发出了对该频道的DELETE请求。它获取not_full锁(以防止写入),通知not_empty锁
  4. 我真的不明白......如果线程得到通知,为什么它不会解锁?

2 个答案:

答案 0 :(得分:1)

篡改Queue的内部锁定似乎是一个坏主意。如何仅根据Queue的官方界面来制定问题?

例如,要模拟关闭队列,请执行self._queue.put(None)或其他一些特殊值。获取此特殊值的等待线程知道队列已关闭。问题是,特殊值不再在队列中,可能有更多线程需要查看;但这很容易解决:当一个线程获得特殊值时,它会立即将它再次放入队列中。

答案 1 :(得分:0)

我使用了虚拟插入。

    self._queue.put(None)

这会唤醒另一个线程,我知道我们正在关闭该频道,因为该消息为无。