簡體   English   中英

Python中如何分別啟動和停止多處理進程?

[英]How to separately start and stop multiprocessing processes in Python?

我使用專用的 Python (3.8) 庫通過 USB 端口控制電機驅動器。

電機控制驅動器制造商(ODrive)提供的 Python 庫允許單個 Python 進程控制一個或多個驅動器。

但是,我想運行 3 個進程,每個進程控制 1 個驅動器。

在研究了各種選項(我首先考慮了虛擬機、Docker 容器和多線程)之后,我開始相信最簡單的方法是使用multiprocessing

我的問題是我需要一種方法來管理(即獨立啟動、監控和停止)多個進程。 其背后的實際原因是電機連接到不同的設置。 例如,如果出現故障,每個設置都必須能夠單獨停止和重新啟動,但其他正在運行的設置不應受到此操作的影響。

在閱讀了互聯網和 Stack Overflow 之后,我現在了解了如何創建處理Pool 、如何將進程與處理器內核關聯、如何啟動進程池以及排隊/加入它們(我不需要后者) .

我不知道如何獨立管理它們。 如何在不影響其他進程執行的情況下分別啟動/停止不同進程? 是否有庫來管理它們(甚至可能使用 GUI)?

您可以像這樣手動創建多個multriprocessing.Process實例:

def my_func(a, b):
    pass

p = multiprocessing.Process(target=my_func, args=(100, 200)
p.start()

並使用多處理原語QueueEventCondition等對其進行管理。有關詳細信息,請參閱官方文檔: https://docs.python.org/3/library/multiprocessing.ZFC35FDC70D5FC69D269883A822E

在以下示例中,多個進程獨立啟動和停止。 Event用於確定何時停止進程。 Queue用於從子進程傳遞到主進程的結果。

import multiprocessing
import queue
import random
import time


def worker_process(
    process_id: int,
    results_queue: multiprocessing.Queue,
    to_stop: multiprocessing.Event,
):

    print(f"Process {process_id} is started")
    while not to_stop.is_set():
        print(f"Process {process_id} is working")
        time.sleep(0.5)
        result = random.random()
        results_queue.put((process_id, result))

    print(f"Process {process_id} exited")


process_pool = []
result_queue = multiprocessing.Queue()
while True:
    if random.random() < 0.3:
        # staring a new process
        process_id = random.randint(0, 10_000)
        to_stop = multiprocessing.Event()
        p = multiprocessing.Process(
            target=worker_process, args=(process_id, result_queue, to_stop)
        )
        p.start()
        process_pool.append((p, to_stop))

    if random.random() < 0.2:
        # closing a random process
        if process_pool:
            process, to_stop = process_pool.pop(
                random.randint(0, len(process_pool) - 1)
            )
            to_stop.set()
            process.join()

    try:
        p_id, result = result_queue.get_nowait()
        print(f"Completed: process_id={p_id} result={result}")
    except queue.Empty:
        pass

    time.sleep(1)

我可能會做這樣的事情:

import random
import time
from multiprocessing import Process, Queue


class MotorProcess:
    def __init__(self, name, com_related_params):
        self.name = name
        # Made up some parameters relating to communication
        self._params = com_related_params
        self._command_queue = Queue()
        self._status_queue = Queue()
        self._process = None

    def start(self):
        if self._process and self._process.is_alive():
            return
        self._process = Process(target=self.run_processing,
                                args=(self._command_queue, self._status_queue,
                                      self._params))
        self._process.start()

    @staticmethod
    def run_processing(command_queue, status_queue, params):
        while True:
            # Check for commands
            if not command_queue.empty():
                msg = command_queue.get(block=True, timeout=0.05)
                if msg == "stop motor":
                    status_queue.put("Stopping motor")
                elif msg == "exit":
                    return
                elif msg.startswith("move"):
                    status_queue.put("moving motor to blah")
                    # TODO: msg parsing and move motor
                else:
                    status_queue.put("unknown command")

            # Update status
            # TODO: query motor status
            status_queue.put(f"Motor is {random.randint(0, 100)}")
            time.sleep(0.5)

    def is_alive(self):
        if self._process and self._process.is_alive():
            return True
        return False

    def get_status(self):
        if not self.is_alive():
            return ["not running"]
        # Empty the queue
        recent = []
        while not self._status_queue.empty():
            recent.append(self._status_queue.get(False))
        return recent

    def stop_process(self):
        if not self.is_alive():
            return
        self._command_queue.put("exit")
        # Empty the stats queue otherwise it could potentially stop
        # the process from closing.
        while not self._status_queue.empty():
            self._status_queue.get()

        self._process.join()

    def send_command(self, command):
        self._command_queue.put(command)


if __name__ == "__main__":
    processes = [MotorProcess("1", None), MotorProcess("2", None)]

    while True:
        cmd = input()
        if cmd == "start 1":
            processes[0].start()
        elif cmd == "move 1 to 100":
            processes[0].send_command("move to 100")
        elif cmd == "exit 1":
            processes[0].stop_process()
        else:
            for n, p in enumerate(processes):
                print(f"motor {n + 1}", end="\n\t")
                print("\n\t".join(p.get_status()))

未准備好生產(例如,沒有異常處理,沒有正確的命令解析等),但顯示了這個想法。 有問題就大聲喊:D

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM