简体   繁体   中英

Python how to make fast multiprocessing program?

I made a simple GUI tool controlling a robot but there was GUI lock up during robot was operating. I added sub-process taking whole robot controlling. After adding sub-process, GUI lock up was cleared. However it takes very long time to see the response of robot after sending command. Sometimes it takes a few seconds. Before adding sub-process, it didn't exceed hundreds milliseconds at max.

I implemented sub-process like below. GUI put command in the cmd_q of sub-process. Sub-process is activated in GUI init. Is there any way to improve the response speed?

class ProcRobotControl(Process):
    def __init__(self):
        super().__init__()
        self.daemon = True
        self.cmd_q = Queue()

    def run(self):
        while True:
            while self.cmd_q.empty():
                pass

            cmd = self.cmd_q.get()

So-called "busy-waiting" (your line while self.cmd_q.empty():) is discouraged in most situations, because the waiting process will eat resources. If the event that your process is waiting for is created on the same machine, then your waiting process actually prevents the event from being created quickly.

If that is indeed the problem (impossible for me to test without more code) then a quick-and-dirty solution would be to replace the "pass" in the busy-wait with an "os.sched_yield()", thus making your waiting-thread relinquish the cpu and allow the gui-thread to do work.

Cleaner suggestion using multiprocessing : The default-behaviour of a multiprocessing Queue's get is to block until an element is available (see here: https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue.get ), so you can skip the unreliable queue.empty()-check altogether

Cleaner suggestion using pyqt5 : The framework already has its own threading-solution with the QThread object. This is probably better for preventing bad interactions with the gui-loop, so try if it solves your problem.

Just to provide additional info provided in the answer posted by julaine:

First, you should read carefully the documentation for the multiprocessing.Queue . You will see that it clearly states that the empty method is not reliable. You should not be using this in general and definitely not the way you are using it, which is non-productive CPU-cycle burning.

Based on the minimal code that you have posted, I see no reason to even test to see whether there is an item in the queue; you should just be doing a blocking get :

    def run(self):
        while True:
            cmd = self.cmd_q.get() # blocking get is the default here

In this way you are not burning up CPU cycles waiting for the next command.

I would also recommend not deriving your class from class multiprocessing.Process , which limits its reusability. For example, you might want to use the same logic with threading instead of multiprocessing, substituting q queue.Queue instance for a multiprocessing.Queue or multiprocessing.JoinableQueue instance:

class ProcRobotControl:
    def __init__(self, cmd_q):
        self.cmd_q = cmd_q

    def run(self):
        while True:
            cmd = self.cmd_q.get()
            print(cmd)
            self.cmd_q.task_done()

if __name__ == '__main__':
    # Use ProcRobot as a child process:
    import multiprocessing

    q1 = multiprocessing.JoinableQueue()
    proc_robot_control = ProcRobotControl(q1)
    p = multiprocessing.Process(target=proc_robot_control.run, daemon=True)
    p.start()
    q1.put('a')
    q1.put('b')
    # Wait for all commands to be procssed:
    q1.join()

    # Use ProcRobot as a child thread:
    import threading
    import queue

    q2 = queue.Queue()
    proc_robot_control = ProcRobotControl(q2)
    t = threading.Thread(target=proc_robot_control.run, daemon=True)
    t.start()
    q2.put('c')
    q2.put('d')
    # Wait for all commands to be procssed:
    q2.join()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM