Python 多处理建议和停止进程

Python 多处理建议和停止进程,python,multiprocessing,Python,Multiprocessing,我正在尝试实施一个系统,其中: Actors生成数据 Replay是一个管理由参与者生成的数据的类(理论上它比下面的代码做得更多,但我在这里发布它时保持了简单) Learner使用Replay类的数据(有时更新Replay的一些数据) 为了实现这一点,我将生成的参与者数据附加到一个多处理.Queue,我使用一个进程将数据推送到重播中。我使用了一个multiprocessing.BaseManager来共享Replay 这是我的实现(代码正在运行): 导入时间 随机输入 从集合导入deque

我正在尝试实施一个系统,其中:

  • Actors
    生成数据
  • Replay
    是一个管理由
    参与者生成的数据的类(理论上它比下面的代码做得更多,但我在这里发布它时保持了简单)
  • Learner
    使用Replay类的数据(有时更新
    Replay
    的一些数据)
为了实现这一点,我将生成的参与者数据附加到一个
多处理.Queue
,我使用一个进程将数据推送到重播中。我使用了一个
multiprocessing.BaseManager
来共享
Replay

这是我的实现(代码正在运行):

导入时间
随机输入
从集合导入deque
导入torch.multiprocessing作为mp
从multiprocessing.managers导入BaseManager
T=20
B=5
重播\u最小\u大小=10
重播\u最大\u大小=100
班级演员:
定义初始化(自、全局缓冲区、秩):
self.rank=等级
self.local_buffer=[]
self.global\u buffer=全局\u buffer
def运行(自我、数量步数):
对于步进范围(num_步数):
data=f'{self.rank}{step}'
self.local\u buffer.append(数据)
如果len(自本地_缓冲区)>=B:
self.global\u buffer.put(self.local\u buffer)
self.local_buffer=[]
班级学员:
定义初始化(自我,重播):
self.replay=replay
def运行(自我、数量步数):

而self.replay.size()我发现在处理多进程时,最好为每个正在运行的进程设置一个队列。当您准备关闭应用程序时,可以向每个队列发送退出消息(或毒药丸),并干净地关闭每个进程


启动子进程时,通过继承将父队列和子队列传递给新进程。

我将尝试看看是否会实现这一点,但由于目标是使所有数据聚合到重播,因此我认为只有一个队列非常好。为什么你认为最好有几个?我不理解关于子进程、父进程和子队列的句子,你能再解释一下吗?我明白了,我会确保所有子进程都引用了重播队列,从而引用了重播进程。父进程将是第一个启动的进程,子进程将是由父进程启动的进程。在这种情况下,尤其是在使用Actor范式时,父进程应该始终管理它启动的子进程。看看这部电影吧,他们已经实现了很多这方面的东西(队列管理),所以你不必这么做。
import time
import random
from collections import deque
import torch.multiprocessing as mp
from multiprocessing.managers import BaseManager

T = 20
B = 5
REPLAY_MINIMUM_SIZE = 10
REPLAY_MAXIMUM_SIZE = 100


class Actor:
    def __init__(self, global_buffer, rank):
        self.rank = rank
        self.local_buffer = []
        self.global_buffer = global_buffer

    def run(self, num_steps):
        for step in range(num_steps):
            data = f'{self.rank}_{step}'
            self.local_buffer.append(data)

            if len(self.local_buffer) >= B:
                self.global_buffer.put(self.local_buffer)
                self.local_buffer = []


class Learner:
    def __init__(self, replay):
        self.replay = replay

    def run(self, num_steps):
        while self.replay.size() <= REPLAY_MINIMUM_SIZE:
            time.sleep(0.1)
        for step in range(num_steps):
            batch = self.replay.sample(B)
            print(batch)

class Replay:
    def __init__(self, capacity):
        self.memory = deque(maxlen=capacity)

    def push(self, experiences):
        self.memory.extend(experiences)

    def sample(self, n):
        return random.sample(self.memory, n)

    def size(self):
        return len(self.memory)


def send_data_to_replay(global_buffer, replay):
    while True:
        if not global_buffer.empty():
            batch = global_buffer.get()
            replay.push(batch)


if __name__ == '__main__':
    num_actors = 2

    global_buffer = mp.Queue()

    BaseManager.register("ReplayMemory", Replay)
    Manager = BaseManager()
    Manager.start()
    replay = Manager.ReplayMemory(REPLAY_MAXIMUM_SIZE)

    learner = Learner(replay)
    learner_process = mp.Process(target=learner.run, args=(T,))
    learner_process.start()

    actor_processes = []
    for rank in range(num_actors):
        p = mp.Process(target=Actor(global_buffer, rank).run, args=(T,))
        p.start()
        actor_processes.append(p)

    replay_process = mp.Process(target=send_data_to_replay, args=(global_buffer, replay,))
    replay_process.start()

    learner_process.join()
    [actor_process.join() for actor_process in actor_processes]
    replay_process.join()