如何在单独的进程中运行Python自定义对象,所有进程都在共享事件队列中工作?

如何在单独的进程中运行Python自定义对象,所有进程都在共享事件队列中工作?,python,multiprocessing,Python,Multiprocessing,我有4个不同的Python自定义对象和一个事件队列。每个obect都有一个方法,允许它从共享事件队列中检索事件,如果类型是所需的,则对其进行处理,然后将新事件放在同一事件队列中,允许其他进程对其进行处理 这里有一个例子 import multiprocessing as mp class CustomObject: def __init__(events_queue: mp.Queue) -> None: self.events_queue = event_qu

我有4个不同的Python自定义对象和一个事件队列。每个obect都有一个方法,允许它从共享事件队列中检索事件,如果类型是所需的,则对其进行处理,然后将新事件放在同一事件队列中,允许其他进程对其进行处理

这里有一个例子

import multiprocessing as mp

class CustomObject:

    def __init__(events_queue: mp.Queue) -> None:
        self.events_queue = event_queue

    def process_events_queue() -> None:
        event = self.events_queue.get()
        if type(event) == SpecificEventDataTypeForThisClass:
            # do something and create a new_event
            self.events_queue.put(new_event)
        else:
            self.events_queue.put(event)

    # there are other methods specific to each object
这4个对象有特定的任务要做,但它们都共享相同的结构。因为我需要“模拟”生产条件,所以我希望它们同时运行,彼此独立

如果可能的话,这里只是我想做的一个例子

import multiprocessing as mp
import CustomObject

if __name__ == '__main__':

    events_queue = mp.Queue()

    data_provider = mp.Process(target=CustomObject, args=(events_queue,))
    portfolio = mp.Process(target=CustomObject, args=(events_queue,))
    engine = mp.Process(target=CustomObject, args=(events_queue,))
    broker = mp.Process(target=CustomObject, args=(events_queue,))

    while True:
        data_provider.process_events_queue()
        portfolio.process_events_queue()
        engine.process_events_queue()
        broker.process_events_queue()
我的想法是在一个单独的进程中运行每个对象,允许它们与通过事件队列共享的事件通信。所以我的问题是,我该怎么做


问题是
obj=mp.Process(target=CustomObject,args=(events\u queue,)
返回一个流程实例,我无法从中访问CustomObject方法。还有,是否有更智能的方法来实现我想要的功能?

流程需要一个函数来运行,该函数定义了流程实际执行的操作。一旦这个函数退出(并且没有非守护进程线程),进程就完成了。这类似于Python本身总是执行
\uuuu主脚本的方式

如果您执行
mp.Process(target=CustomObject,args=(events\u queue,)
,它只告诉流程调用
CustomObject
——它实例化一次,然后就完成了。这不是您想要的,除非类在实例化时实际执行工作-这是一个坏主意,因为其他原因

相反,您必须定义一个主函数或方法来处理您需要的内容:“与通过事件队列共享的事件通信”。此函数应侦听队列并根据接收到的事件采取操作

一个简单的实现如下所示:

import os, time
from multiprocessing import Queue, Process


class Worker:
    # separate input and output for simplicity
    def __init__(self, commands: Queue, results: Queue):
        self.commands = commands
        self.results = results

    # our main function to be run by a process
    def main(self):
        # each process should handle more than one command
        while True:
            value = self.commands.get()
            # pick a well-defined signal to detect "no more work"
            if value is None:
                self.results.put(None)
                break
            # do whatever needs doing
            result = self.do_stuff(value)
            print(os.getpid(), ':', self, 'got', value, 'put', result)
            time.sleep(0.2)  # pretend we do something
            # pass on more work if required
            self.results.put(result)

    # placeholder for what needs doing
    def do_stuff(self, value):
        raise NotImplementedError
这是一个只处理事件的类的模板。必须重载
do\u stuff
方法来定义实际发生的情况

class AddTwo(Worker):
    def do_stuff(self, value):
        return value + 2


class TimesThree(Worker):
    def do_stuff(self, value):
        return value * 3


class Printer(Worker):
    def do_stuff(self, value):
        print(value)
这已经定义了完整的工作流程有效负载:
process(target=TimesThree(in_queue,out_queue).main)
在流程中调度
main
方法,侦听和响应命令

运行此操作主要需要连接各个组件:

if __name__ == '__main__':
    # bookkeeping of resources we create
    processes = []
    start_queue = Queue()
    # connect our workers via queues
    queue = start_queue
    for element in (AddTwo, TimesThree, Printer):
        instance = element(queue, Queue())
        # we run the main method in processes
        processes.append(Process(target=instance.main))
        queue = instance.results
    # start all processes
    for process in processes:
        process.start()
    # send input, but do not wait for output
    start_queue.put(1)
    start_queue.put(248124)
    start_queue.put(-256)
    # send shutdown signal
    start_queue.put(None)
    # wait for processes to shutdown
    for process in processes:
        process.join()

请注意,这不需要类。您还可以为类似效果编写函数,只要所有内容都可以进行pickle:

import os, time
from multiprocessing import Queue, Process

def main(commands, results, do_stuff):
    while True:
        value = commands.get()
        if value is None:
            results.put(None)
            break
        result = do_stuff(value)
        print(os.getpid(), ':', do_stuff, 'got', value, 'put', result)
        time.sleep(0.2)
        results.put(result)

def times_two(value):
    return value * 2


if __name__ == '__main__':
    in_queue, out_queue = Queue(), Queue()
    worker = Process(target=main, args=(in_queue, out_queue, times_two))
    worker.start()
    for message in (1, 3, 5, None):
        in_queue.put(message)
    while True:
        reply = out_queue.get()
        if reply is None:
            break
        print('result:', reply)

流程需要运行一个函数,该函数定义了流程实际执行的操作。一旦这个函数退出(并且没有非守护进程线程),进程就完成了。这类似于Python本身总是执行
\uuuu主脚本的方式

如果您执行
mp.Process(target=CustomObject,args=(events\u queue,)
,它只告诉流程调用
CustomObject
——它实例化一次,然后就完成了。这不是您想要的,除非类在实例化时实际执行工作-这是一个坏主意,因为其他原因

相反,您必须定义一个主函数或方法来处理您需要的内容:“与通过事件队列共享的事件通信”。此函数应侦听队列并根据接收到的事件采取操作

一个简单的实现如下所示:

import os, time
from multiprocessing import Queue, Process


class Worker:
    # separate input and output for simplicity
    def __init__(self, commands: Queue, results: Queue):
        self.commands = commands
        self.results = results

    # our main function to be run by a process
    def main(self):
        # each process should handle more than one command
        while True:
            value = self.commands.get()
            # pick a well-defined signal to detect "no more work"
            if value is None:
                self.results.put(None)
                break
            # do whatever needs doing
            result = self.do_stuff(value)
            print(os.getpid(), ':', self, 'got', value, 'put', result)
            time.sleep(0.2)  # pretend we do something
            # pass on more work if required
            self.results.put(result)

    # placeholder for what needs doing
    def do_stuff(self, value):
        raise NotImplementedError
这是一个只处理事件的类的模板。必须重载
do\u stuff
方法来定义实际发生的情况

class AddTwo(Worker):
    def do_stuff(self, value):
        return value + 2


class TimesThree(Worker):
    def do_stuff(self, value):
        return value * 3


class Printer(Worker):
    def do_stuff(self, value):
        print(value)
这已经定义了完整的工作流程有效负载:
process(target=TimesThree(in_queue,out_queue).main)
在流程中调度
main
方法,侦听和响应命令

运行此操作主要需要连接各个组件:

if __name__ == '__main__':
    # bookkeeping of resources we create
    processes = []
    start_queue = Queue()
    # connect our workers via queues
    queue = start_queue
    for element in (AddTwo, TimesThree, Printer):
        instance = element(queue, Queue())
        # we run the main method in processes
        processes.append(Process(target=instance.main))
        queue = instance.results
    # start all processes
    for process in processes:
        process.start()
    # send input, but do not wait for output
    start_queue.put(1)
    start_queue.put(248124)
    start_queue.put(-256)
    # send shutdown signal
    start_queue.put(None)
    # wait for processes to shutdown
    for process in processes:
        process.join()

请注意,这不需要类。您还可以为类似效果编写函数,只要所有内容都可以进行pickle:

import os, time
from multiprocessing import Queue, Process

def main(commands, results, do_stuff):
    while True:
        value = commands.get()
        if value is None:
            results.put(None)
            break
        result = do_stuff(value)
        print(os.getpid(), ':', do_stuff, 'got', value, 'put', result)
        time.sleep(0.2)
        results.put(result)

def times_two(value):
    return value * 2


if __name__ == '__main__':
    in_queue, out_queue = Queue(), Queue()
    worker = Process(target=main, args=(in_queue, out_queue, times_two))
    worker.start()
    for message in (1, 3, 5, None):
        in_queue.put(message)
    while True:
        reply = out_queue.get()
        if reply is None:
            break
        print('result:', reply)

你能说明你想要实现什么吗?对象要么通过队列通信,要么通过调用方法通信——但您的描述提到了这两种方法。为什么要使用进程来实例化对象,而不是运行已安装的对象?也就是说,为什么不做类似于
worker=CustomObject(事件队列)的事情;mp.Process(target=worker.Process\u events\u queue)
?您的解决方案建议这4个对象都在同一个进程中,只有对
.Process\u events\u queue()
的调用在单独的进程中。我想问的是,是否有可能让对象生活在“始终处于独立进程”中,通过共享队列彼此通信。进程必须做些什么,不能让对象单独生活。由于您希望对象通过队列进行通信,
process\u events\u queue
是唯一这样做的,因此您应该在流程中运行它。它可能需要推广,是的,但如何做到这一点对于一般情况来说是一个非常广泛的问题。因此,我不能让n个不同的Python进程处于空闲状态,无限期地等待从另一个进程接收通信/工作?是的,你可以,通过在类似于
process\u events\u queue
的流程中作为一个无限循环运行。您能说明您想要实现什么吗?对象要么通过队列通信,要么通过调用方法通信——但您的描述提到了这两种方法。为什么要使用进程来实例化对象,而不是运行已安装的对象?也就是说,为什么不做类似于
worker=CustomObject(事件队列)的事情;mp.Process(target=worker.Process\u events\u queue)
?您的解决方案建议这4个对象都在同一个进程中,只有对
.Process\u events\u queue()
的调用在单独的进程中。我想问的是,是否有可能让对象生活在“始终处于独立进程”中,通过共享队列彼此通信