Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python阻塞堆栈多线程_Python_Multithreading - Fatal编程技术网

Python阻塞堆栈多线程

Python阻塞堆栈多线程,python,multithreading,Python,Multithreading,我正在学习python中的多线程,我试图实现的是一个堆栈类,它追加(v)等待直到大小未满,以及一个pop()等待直到堆栈不为空。我的实现如下,它看起来正确吗 import threading class BlockingStack(object): def __init__(self,max_size=1000): self.max_size = max_size self.stack = [] self.notifynonempty =

我正在学习python中的多线程,我试图实现的是一个堆栈类,它追加(v)等待直到大小未满,以及一个pop()等待直到堆栈不为空。我的实现如下,它看起来正确吗

import threading
class BlockingStack(object):
    def __init__(self,max_size=1000):
        self.max_size = max_size
        self.stack = []
        self.notifynonempty = threading.Condition()
        self.notifynotfull = threading.Condition()

    def append(self,v):
        self.notifynonempty.acquire()
        while len(self.stack) == self.max_size:
            self.notifynotfull.wait()
        self.stack.append(v)
        if len(self.stack) == 1:
            self.notifynonempty.notify()
        self.notifynonempty.release()

    def pop(self):
        self.notifynotfull.acquire()
        while len(self.stack) == 0:
            self.notifynonempty.wait()
        v = self.stack.pop()
        if len(self.stack)==self.max_size - 1:
            self.notifynotfull.notify()
        self.notifynotfull.release()
        return v

追加中的第一个问题如下:

self.notifynonempty.acquire()
当您要在另一个同步对象上阻塞或将要死锁时,切勿
获取
条件并保持它。将其移动到其他条件的
等待
成功后


下一步:

试图在你没有获得的条件下等待,这是一场比赛,大致相当于一开始就没有条件。在循环之前,您需要
获取该条件


此外,如果任何地方出现异常,您将泄漏锁,这将使您的程序死锁。您可以通过仔细的
尝试
/
最终
工作来解决这个问题,但是只使用
with
语句要简单得多,如文档中所示


因此:

pop
的问题与此相反


但是,对于大多数使用模式,让两个条件共享相同的互斥将更有效,如下所示:

self.mutex = threading.Lock()
self.notifynonempty = threading.Condition(self.mutex)
self.notifynotfull = threading.Condition(self.mutex)
import queue

class Stack(queue.Queue):
    def _init(self, maxsize):
        self.queue = []
    def _qsize(self):
        return len(self.queue)
    def _put(self, item):
        self.queue.append(item)
    def _get(self):
        return self.queue.pop()
…这也让事情变得更简单

另外,不需要在
notify()
之前进行检查。在某些情况下(只有一个生产者,或者只有一个消费者),它可能会使事情变得更有效,但它可能会使其他情况变得更慢,使事情变得更复杂,并且在调试过程中更难检测到竞争。所以,我暂时不谈了。一旦一切正常,就用实际使用模式编写一些基准测试,并用两种方法进行测试(当然,只使用附加检查和pop检查)


作为旁注,如果您这样做不是为了了解条件,而是因为您需要一个自同步堆栈,那么已经提供了这一点

即使没有,你也可以这样写:

self.mutex = threading.Lock()
self.notifynonempty = threading.Condition(self.mutex)
self.notifynotfull = threading.Condition(self.mutex)
import queue

class Stack(queue.Queue):
    def _init(self, maxsize):
        self.queue = []
    def _qsize(self):
        return len(self.queue)
    def _put(self, item):
        self.queue.append(item)
    def _get(self):
        return self.queue.pop()

关于这一点,现在我想起来了,文档链接到,它应该提供可靠的示例代码。它比您需要的要复杂一点,所有的block-vs.-try-vs.-timeout选项,以及整个
task\u-done
/
join
功能,但它仍然非常清晰易读。

感谢您的回答,我还有一个问题,notifyNoneEmpty和notifynonfull使用相同的底层锁对象时。如果我们在pop()为空时调用它,然后另一个线程调用append(),这会是一个死锁吗?我想我从python文档中得到了答案,wait方法释放底层线程lock@DDD是,
wait
释放基础锁,然后在唤醒(或超时)时重新请求。因此,您必须在等待之前获得基础锁。(另外,释放、睡眠、唤醒和获取是原子的,这一点很重要;这就是为什么不能用事件来代替条件。)
import queue

class Stack(queue.Queue):
    def _init(self, maxsize):
        self.queue = []
    def _qsize(self):
        return len(self.queue)
    def _put(self, item):
        self.queue.append(item)
    def _get(self):
        return self.queue.pop()