Python 关于使用Queue()/deque()和类变量进行通信的进程与线程,以及;“毒丸”;

Python 关于使用Queue()/deque()和类变量进行通信的进程与线程,以及;“毒丸”;,python,python-3.x,multiprocessing,python-multithreading,python-multiprocessing,Python,Python 3.x,Multiprocessing,Python Multithreading,Python Multiprocessing,我想创建一个线程或一个进程,它永远在While-True循环中运行 我需要以队列的形式向工作者发送和接收数据,可以是multiprocessing.Queue()或collections.deque()。我更喜欢使用collections.deque(),因为它要快得多 我还需要能够最终杀死worker(因为它在while-True循环中运行)。下面是我编写的一些测试代码,以尝试理解线程、进程、队列和deque之间的差异 import time from multiprocessing impo

我想创建一个线程或一个进程,它永远在While-True循环中运行

我需要以队列的形式向工作者发送和接收数据,可以是multiprocessing.Queue()或collections.deque()。我更喜欢使用collections.deque(),因为它要快得多

我还需要能够最终杀死worker(因为它在while-True循环中运行)。下面是我编写的一些测试代码,以尝试理解线程、进程、队列和deque之间的差异

import time
from multiprocessing import Process, Queue
from threading import Thread
from collections import deque

class ThreadingTest(Thread):

    def __init__(self, q):
        super(ThreadingTest, self).__init__()
        self.q = q
        self.toRun = False

    def run(self):
        print("Started Thread")
        self.toRun = True
        while self.toRun:
            if type(self.q) == type(deque()):
                if self.q:
                    i = self.q.popleft()
                    print("Thread deque: " + str(i))
            elif type(self.q) == type(Queue()):
                if not self.q.empty():
                    i = self.q.get_nowait()
                    print("Thread Queue: " + str(i))

    def stop(self):
        print("Trying to stop Thread")
        self.toRun = False
        while self.isAlive():
            time.sleep(0.1)
        print("Stopped Thread")

class ProcessTest(Process):

    def __init__(self, q):
        super(ProcessTest, self).__init__()
        self.q = q
        self.toRun = False
        self.ctr = 0

    def run(self):
        print("Started Process")
        self.toRun = True
        while self.toRun:
            if type(self.q) == type(deque()):
                if self.q:
                    i = self.q.popleft()
                    print("Process deque: " + str(i))
            elif type(self.q) == type(Queue()):
                if not self.q.empty():
                    i = self.q.get_nowait()
                    print("Process Queue: " + str(i))

    def stop(self):
        print("Trying to stop Process")
        self.toRun = False
        while self.is_alive():
            time.sleep(0.1)
        print("Stopped Process")

if __name__ == '__main__':
    q = Queue()
    t1 = ProcessTest(q)
    t1.start()

    for i in range(10):
        if type(q) == type(deque()):
            q.append(i)
        elif type(q) == type(Queue()):
            q.put_nowait(i)
        time.sleep(1)
    t1.stop()
    t1.join()

    if type(q) == type(deque()):
        print(q)
    elif type(q) == type(Queue()):
        while q.qsize() > 0:
            print(str(q.get_nowait()))
如您所见,t1可以是ThreadingTest,也可以是ProcessTest。此外,传递给它的队列可以是multiprocessing.queue或collections.deque

ThreadingTest与队列或deque()一起工作。调用stop()方法时,它也会正确终止run()

Started Thread
Thread deque: 0
Thread deque: 1
Thread deque: 2
Thread deque: 3
Thread deque: 4
Thread deque: 5
Thread deque: 6
Thread deque: 7
Thread deque: 8
Thread deque: 9
Trying to stop Thread
Stopped Thread
deque([])
ProcessTest只有在队列类型为multiprocessing.queue时才能从队列中读取。它不适用于collections.deque。此外,我无法使用stop()终止进程


我想弄清楚为什么?还有,在进程中使用deque的最佳方式是什么?以及,我如何使用某种stop()终止进程方法。

您不能使用
collections.deque
在两个
多处理.Process
实例之间传递数据,因为
collections.deque
不支持进程。
多处理.Queue
将其内容写入内部的
多处理.Pipe
,这意味着其中的数据可以排队一旦处理并在另一个。
collections中检索。deque
没有这种管道,因此无法工作。当您在一个进程中写入
deque
时,另一个进程中的
deque
实例将完全不受影响;它们是完全独立的实例

类似的问题也发生在您的
stop()上
方法。您正在主进程中更改
toRun
的值,但这根本不会影响子进程。它们是完全独立的实例。结束子进程的最佳方法是向
队列发送一些哨兵。当您在子进程中获得哨兵时,打破无限循环:

def run(self):
    print("Started Process")
    self.toRun = True
    while self.toRun:
        if type(self.q) == type(deque()):
            if self.q:
                i = self.q.popleft()
                print("Process deque: " + str(i))
        elif type(self.q) == type(Queue()):
            if not self.q.empty():
                i = self.q.get_nowait()
                if i is None:  
                    break  # Got sentinel, so break
                print("Process Queue: " + str(i))

def stop(self):
    print("Trying to stop Process")
    self.q.put(None)  # Send sentinel
    while self.is_alive():
        time.sleep(0.1)
    print("Stopped Process")
编辑:

如果您确实需要两个进程之间的
deque
语义,您可以使用在
Manager
进程中创建一个共享
deque
,并且您的每个
process
实例将获得一个
代理:

import time
from multiprocessing import Process
from multiprocessing.managers import SyncManager
from collections import deque

SyncManager.register('deque', deque)

def Manager():
    m = SyncManager()
    m.start()
    return m

class ProcessTest(Process):
    def __init__(self, q):
        super(ProcessTest, self).__init__()
        self.q = q
        self.ctr = 0

    def run(self):
        print("Started Process")
        self.toRun = True
        while self.toRun:
            if self.q._getvalue():
                i = self.q.popleft()
                if i is None:
                    break
                print("Process deque: " + str(i))

    def stop(self):
        print("Trying to stop Process")
        self.q.append(None)
        while self.is_alive():
            time.sleep(0.1)
        print("Stopped Process")

if __name__ == '__main__':
    m = Manager()
    q = m.deque()
    t1 = ProcessTest(q)
    t1.start()

    for i in range(10):
        q.append(i)
        time.sleep(1)
    t1.stop()
    t1.join()

    print(q)

请注意,这可能不会比
多处理.Queue
更快,但是,因为每次访问
deque
都要付出IPC代价。它也是一种不太自然的数据结构,无法像现在这样传递消息。

我可以通过以下方式终止进程:创建另一个类变量:self.killQ=Queue():我可以在self.killQ.empty()时执行while-toRun():在stop()方法中,我可以在队列中附加一个伪对象,比如self.killQ.put_nowait(0),但是…为什么像toRun这样的类变量不起作用呢?它与stop()中self.toRun=False的赋值有关吗方法?对流程的另一个观察。我可以在流程中使用deque传递内容,而且效果很好。我只是不能使用deque在流程之间进行通信(本例中为main和ProcessTest)。顺便说一句,在消费之前检查
队列
是否为空通常是一种不好的做法。它很容易受到竞争条件的影响,因为如果多个线程正在从
队列
读取数据,那么在您检查其大小和实际尝试从中获取
时,它可能会变为空。在这种情况下,我认为你最好直接调用
q.get()
。这样,当你等待
队列中的某个东西时,你就不会不断循环,从而在孩子身上使用CPU。我也会在self.is\u活着时删除
:time.sleep(0.1)
调用
stop
,因为你正在调用
join()
在进程/线程上。您不妨调用
join()
。这是我需要知道的。谢谢!
import time
from multiprocessing import Process
from multiprocessing.managers import SyncManager
from collections import deque

SyncManager.register('deque', deque)

def Manager():
    m = SyncManager()
    m.start()
    return m

class ProcessTest(Process):
    def __init__(self, q):
        super(ProcessTest, self).__init__()
        self.q = q
        self.ctr = 0

    def run(self):
        print("Started Process")
        self.toRun = True
        while self.toRun:
            if self.q._getvalue():
                i = self.q.popleft()
                if i is None:
                    break
                print("Process deque: " + str(i))

    def stop(self):
        print("Trying to stop Process")
        self.q.append(None)
        while self.is_alive():
            time.sleep(0.1)
        print("Stopped Process")

if __name__ == '__main__':
    m = Manager()
    q = m.deque()
    t1 = ProcessTest(q)
    t1.start()

    for i in range(10):
        q.append(i)
        time.sleep(1)
    t1.stop()
    t1.join()

    print(q)