我制作了一个简单的GUI工具来控制机器人,但在机器人运行期间出现了GUI锁定。我增加了整个机器人控制的子过程。添加子进程后,GUI锁定被清除。然而,在发出命令后,要花很长时间才能看到机器人的响应。有时需要几秒钟。在添加子进程之前,的最大值不超过数百毫秒
我实现了如下子流程。GUI将命令放入子进程的cmd_q中。子进程在GUI初始化中被激活。有什么方法可以提高响应速度吗?
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()
所谓的"忙着等待";(您的行whileself.cmd_q.empty((:(在大多数情况下是不鼓励的,因为等待过程会消耗资源。如果您的进程正在等待的事件是在同一台机器上创建的,那么您的等待进程实际上会阻止事件的快速创建。
如果这确实是问题所在(我不可能在没有更多代码的情况下进行测试(,那么一个快速而肮脏的解决方案将是替换";通过";在繁忙的等待中;os.sched_yield((";,从而使等待线程放弃cpu,并允许gui线程执行工作。
使用多处理的清理建议:多处理队列get的默认行为是阻塞,直到元素可用(请参见此处:https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue.get),这样您就可以跳过不可靠的队列。empty((-完全检查
使用pyqt5的更干净的建议:框架已经有了自己的带有QThread对象的线程解决方案。这可能对防止与gui循环的不良交互更好,所以如果它解决了您的问题,请尝试。
只是为了提供julaine发布的答案中提供的额外信息:
首先,您应该仔细阅读multiprocessing.Queue
的文档。您将看到它清楚地表明empty
方法是不可靠的。你不应该在一般情况下使用它,也绝对不是你使用它的方式,这是非生产性的CPU周期燃烧。
根据您发布的最小代码,我认为没有理由测试队列中是否有项目;你应该只是做一个阻止get
:
def run(self):
while True:
cmd = self.cmd_q.get() # blocking get is the default here
这样就不会占用等待下一个命令的CPU周期。
我还建议不要从类multiprocessing.Process
派生类,这限制了它的可重用性。例如,您可能希望在线程而不是多处理中使用相同的逻辑,将qqueue.Queue
实例替换为multiprocessing.Queue
或multiprocessing.JoinableQueue
实例:
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()