gpt4 book ai didi

python - 后台进程锁定 GUI Python

转载 作者:太空宇宙 更新时间:2023-11-03 14:25:08 25 4
gpt4 key购买 nike

我有一个后台 Process(使用 multiprocessing 中的 Process)将对象推送到我的 GUI,但是这个后台进程一直锁定GUI 和正在推送的更改永远不会显示。对象被放入我的队列,但是我的 GUI 中的更新方法没有被定期调用。我该怎么做才能更规律地更新 GUI?我的 GUI 是用 Tkinter 编写的。

我的后台进程有一个无限循环,因为我总是需要不断读取 USB 端口以获取更多数据,所以基本上我的代码如下所示:

TracerAccess.py

import usb
from types import *
import sys
from multiprocessing import Process, Queue
import time


__idVendor__ = 0xFFFF
__idProduct__ = 0xFFFF

END_POINT = 0x82

def __printHEXList__(list):
print ' '.join('%02x' % b for b in list)

def checkDeviceConnected():
dev = usb.core.find(idVendor=__idVendor__, idProduct=__idProduct__)
if dev is None:
return False
else:
return True

class LowLevelAccess():
def __init__(self):
self.rawIn = []
self.tracer = usb.core.find(idVendor=__idVendor__, idProduct=__idProduct__)
if self.tracer is None:
raise ValueError("Device not connected")
self.tracer.set_configuration()

def readUSB(self):
"""
This method reads the USB data from the simtracer.
"""
try:
tmp = self.tracer.read(END_POINT, 10000,None, 100000).tolist()
while(self.checkForEmptyData(tmp)):
tmp = self.tracer.read(END_POINT, 10000,None, 100000).tolist()
self.rawIn = tmp
except:
time.sleep(1)
self.readUSB()

def checkForEmptyData(self, raw):
if(len(raw) == 10 or raw[10] is 0x60 or len(raw) == 11):
return True
else:
return False

class DataAbstraction:
def __init__(self, queue):
self.queue = queue
self.lowLevel = LowLevelAccess()
def readInput(self):
while True:
self.lowLevel.readUSB()
raw = self.lowLevel.rawIn
self.queue.put(raw)

用户界面.py

from Tkinter import *
import time
import TracerAccess as io
from multiprocessing import Process, Queue
from Queue import Empty
from math import ceil

def findNumberOfLines(message):
lines = message.split("\n")
return len(lines)


class Application(Frame):
def addTextToRaw(self, text, changeColour=False, numberOfLines=0):
self.rawText.config(state=NORMAL)
if changeColour is True:
self.rawText.insert(END,text, 'oddLine')
else:
self.rawText.insert(END,text)
self.rawText.config(state=DISABLED)

def updateRaw(self, text):
if(self.numberOfData() % 2 is not 0):
self.addTextToRaw(text, True)
else:
self.addTextToRaw(text)
def startTrace(self):
self.dataAbstraction = io.DataAbstraction(self.queue)
self.splitProc = Process(target=self.dataAbstraction.readInput())
self.stopButton.config(state="normal")
self.startButton.config(state="disabled")
self.splitProc.start()

def pollQueue(self):
try:
data = self.queue.get(0)
self.dataReturned.append(data)
self.updateRaw(str(data).upper())
self.rawText.tag_config("oddLine", background="#F3F6FA")
except Empty:
pass
finally:
try:
if(self.splitProc.is_alive() is False):
self.stopButton.config(state="disabled")
self.startButton.config(state="normal")
except AttributeError:
pass
self.master.after(10, self.pollQueue)

def stopTrace(self):
self.splitProc.join()
self.stopButton.config(state="disabled")
self.startButton.config(state="normal")

def createWidgets(self):
self.startButton = Button(self)
self.startButton["text"] = "Start"
self.startButton["command"] = self.startTrace
self.startButton.grid(row = 0, column=0)

self.stopButton = Button(self)
self.stopButton["text"] = "Stop"
self.stopButton["command"] = self.stopTrace
self.stopButton.config(state="disabled")
self.stopButton.grid(row = 0, column=1)

self.rawText = Text(self, state=DISABLED, width=82)
self.rawText.grid(row=1, columnspan=4)


def __init__(self, master):
Frame.__init__(self, master)
self.queue = Queue()
self.master.after(10, self.pollQueue)
self.pack()
self.dataReturned = []
self.createWidgets()

def numberOfData(self):
return len(self.dataReturned)

主.py

import ui as ui

if __name__ == "__main__":
root = Tk()
root.columnconfigure(0,weight=1)
app = ui.Application(root)
app.mainloop()

所以后台线程永远不会结束,但是当我结束进程时,UI 在关闭之前开始显示。问题可能是由于我对 TracerAccess.py 模块的设计而出现的,因为我是在移动直接形式的 java 并且几乎没有 python 的设计经验之后开发的。

最佳答案

multiprocess.Process 在内部所做的实际上是一个 fork() ,这有效地复制了您的过程。您或许可以将其形象化为:

                  / ["background" process] -------------\
[main process] --+ +-- [main process]
\ [main process continued] -----------/

p.join() 尝试将两个进程“连接”回一个。这实际上意味着:WAITING后台进程完成。这是 .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._popen.wait 是如何调用的。

这显然不是你想要的。

在 TKinter 的上下文中,您可能想要的是使用 tk 事件循环,例如像这样(Python 3,但该概念也适用于 Python 2)

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()

您不调用 .join(),而是使用 .after() 方法,该方法安排函数在 n< 之后运行 微秒(如果您曾经使用过 Javascript,那么请考虑 setTimeout())来读取队列。

根据 bg() 函数的实际内容,您可能根本不需要 multiprocesing,只需使用 .after() 调度一个函数 可能就足够了。

另见: http://tkinter.unpythonic.net/wiki/UsingTheEventLoop

关于python - 后台进程锁定 GUI Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21888541/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com