后台进程锁定GUI Python
我有一个后台后台进程锁定GUI Python,python,python-2.7,multiprocessing,Python,Python 2.7,Multiprocessing,我有一个后台进程(使用多处理中的进程)将对象推送到我的GUI,但是这个后台进程一直锁定GUI,并且推送的更改永远不会显示。对象被放入我的队列,但是我的GUI中的更新方法没有被定期调用。我可以做些什么使GUI更新更定期?我的GUI是用Tkinter编写的 我的后台进程中有一个无限循环,因为我总是需要不断读取USB端口以获取更多数据,所以我的代码基本上如下所示: TracerAccess.py ui.py Main.py 因此后台线程永远不会结束,但是当我结束进程时,UI在关闭之前开始显示。这个问题
进程
(使用多处理
中的进程
)将对象推送到我的GUI,但是这个后台进程一直锁定GUI,并且推送的更改永远不会显示。对象被放入我的队列,但是我的GUI中的更新方法没有被定期调用。我可以做些什么使GUI更新更定期?我的GUI是用Tkinter编写的
我的后台进程中有一个无限循环,因为我总是需要不断读取USB端口以获取更多数据,所以我的代码基本上如下所示:
TracerAccess.py
ui.py
Main.py
因此后台线程永远不会结束,但是当我结束进程时,UI在关闭之前开始显示。这个问题可能是因为我设计了TracerAccess.py模块,因为我是在移动了直接形式的java之后开发这个模块的,并且几乎没有python的设计经验 在内部,
multiprocess.Process
所做的实际上是一个复制过程,它有效地复制了您的过程。您或许可以将其想象为:
/ ["background" process] -------------\
[main process] --+ +-- [main process]
\ [main process continued] -----------/
p.join()
尝试将两个进程“连接”回一个进程。这实际上意味着:等待后台进程完成。以下是.join()
函数中的实际(完整)代码:
def join(self, timeout=None):
'''
Wait until child process terminates
'''
assert self._parent_pid == os.getpid(), 'can only join a child process'
assert self._popen is not None, 'can only join a started process'
res = self._popen.wait(timeout)
if res is not None:
_current_process._children.discard(self)
注意如何调用self.\u popen.wait
这显然不是你想要的
在TKinter的上下文中,您可能希望使用tk事件循环,例如(Python3,但该概念也适用于Python2)
您不调用.join()
,而是使用.after()
方法,该方法将函数调度为在n
微秒后运行(如果您使用过Javascript,则考虑setTimeout()
)来读取队列
根据bg()
函数的实际内容,您可能根本不需要执行多过程,只需使用.after()
调度函数就足够了
另见:
您使用多处理的基本思想是好的,但可能您使用错了?(例如,立即调用.join()
)。您应该发布代码,最好是@ru毯冒烟者。我已经添加了一个关于该问题和无限循环的类似示例。self.checkqueue()
不能阻止(长时间):使用q.get\u nowait()
而不是q.get()
。下面是我使用了您非常好的示例,并在使用.after()
时添加了更多详细信息,但我的后台进程正在执行一些密集操作,然后在执行密集操作时遇到了困难,after方法将不再被调用。@Dean我已更新示例代码以包含更多输出,它现在在队列上使用get_nowait()
,因此不会阻塞。除此之外,这似乎对我来说效果相当不错……我已经能够用一个较小的示例来复制我的问题,并且我已经更新了问题中的源代码。@Dean一个明显的问题:在ui.py
,Application.startTrace
中,您可以:self.splitProc=Process(target=self.dataAbstraction.readInput())
,您当然不希望括号出现,这会导致函数立即执行,而不是被设置为目标(现在返回值被设置为目标,但由于此函数是一个永无止境的,而True
循环,因此脚本会冻结)。现在目标函数不会执行。这可能就是它存在的原因。
import ui as ui
if __name__ == "__main__":
root = Tk()
root.columnconfigure(0,weight=1)
app = ui.Application(root)
app.mainloop()
/ ["background" process] -------------\
[main process] --+ +-- [main process]
\ [main process continued] -----------/
def join(self, timeout=None):
'''
Wait until child process terminates
'''
assert self._parent_pid == os.getpid(), 'can only join a child process'
assert self._popen is not None, 'can only join a started process'
res = self._popen.wait(timeout)
if res is not None:
_current_process._children.discard(self)
from multiprocessing import Process, Queue
import time, tkinter, queue, random, sys
class Test:
def __init__(self, root):
self.root = root
txt = tkinter.Text(root)
txt.pack()
self.q = Queue()
p = Process(target=self.bg)
p.start()
self.checkqueue()
print('__init__ done', end=' ')
def bg(self):
print('Starting bg loop', end=' ')
n = 42
while True:
# Burn some CPU cycles
(int(random.random() * 199999)) ** (int(random.random() * 1999999))
n += 1
self.q.put(n)
print('bg task finished', end=' ')
def checkqueue(self):
try:
print(self.q.get_nowait(), end=' ')
except queue.Empty:
print('Queue empty', end=' ')
sys.stdout.flush()
# Run myself again after 1 second
self.root.after(1000, self.checkqueue)
root = tkinter.Tk()
Test(root)
root.mainloop()