【发布时间】:2020-10-18 22:57:58
【问题描述】:
我有在 GUI 中显示数据的功能代码,该 GUI 会使用从网络下载的新信息定期更新。 (线程方法的基本代码来自https://www.oreilly.com/library/view/python-cookbook/0596001673/ch09s07.html)我正在使用线程解决方案来改善阻塞 IO 问题(IO 代码未包含在下面的简化代码示例中,因为 IO 似乎不是问题)。如果我将其作为单个实例运行,则代码运行良好。但是,如果我可以使用多处理并行运行代码的多个实例,对每个实例使用不同的输入列表,那将是最方便的。当我尝试实现多处理版本时,每个单独的进程在尝试创建根窗口期间挂起:“window = tk.Tk()”。这是工作的单实例版本:
import threading
import random
import tkinter as tk
import random
import queue #Queue
import multiprocessing
import psutil
class GuiPartBase:
def __init__(self, master, queue, myList, endCommand):
self.queue = queue
# Set up the GUI
a = Label(master, text="Test Tkinter Display!")
a.pack()
## etc
def processIncoming(self):
"""Handle all messages currently in the queue, if any."""
while self.queue.qsize():
try:
result = (self.queue.get(0))
## do stuff with incoming data...
print('result =', result)
except queue.Empty:
# just on general principles...
pass
class ThreadedClientBase:
"""
Launch the main part of the GUI and the worker thread. periodicCall and
endApplication could reside in the GUI part, but putting them here
means that you have all the thread controls in a single place.
"""
def __init__(self, master, mylist):
"""
Start the GUI and the asynchronous threads. We are in the main
(original) thread of the application, which will later be used by
the GUI as well. We spawn a new thread for the worker (I/O).
"""
self.master = master
self.mylist = mylist
# Create the queue
self.queue = queue.Queue()
# Set up the GUI part
self.gui = GuiPartBase(self.master, self.queue, mylist, self.endApplication)
# Set up the thread to do asynchronous I/O
# More threads can also be created and used, if necessary
self.running = 1
self.thread1 = threading.Thread(target=self.workerThread1)
self.thread1.start()
# Start the periodic call in the GUI to check if the queue contains
# anything
self.periodicCall()
def periodicCall(self):
"""
Check every 200 ms if there is something new in the queue.
"""
self.gui.processIncoming()
if not self.running:
# This is the brutal stop of the system. You may want to do
# some cleanup before actually shutting it down.
import sys
sys.exit(1)
self.master.after(200, self.periodicCall)
def workerThread1(self):
"""
This is where we handle the asynchronous I/O. For example, it may be
a 'select( )'. One important thing to remember is that the thread has
to yield control pretty regularly, by select or otherwise.
"""
while self.running:
# simulate asynchronous I/O,
time.sleep(rand.random() * 1.5)
msg = rand.random()
self.queue.put(msg)
def endApplication(self):
self.running = 0
def runGUIthread(threadedList2Get):
print('entering runGUIthread...')
print('list2Get = ', threadedList2Get)
window = tk.Tk()
print('type of window = ', type(window))
print('window = ', window)
client = ThreadedClientBase(window, threadedList2Get)
print('type of client = ', type(client))
print('client = ', client)
window.mainloop()
if __name__ == '__main__':
rand = random.Random()
testList2a = ['abc','def','geh']
testList2b = ['xyz', 'lmn', 'opq']
allLists = [testList2a,testList2b]
runGUIthread(testList2a)
所以,就像我说的,上面的工作 - 一个单一的 tkinter GUI 正确显示,没有错误。但是,如果我尝试使用下面的代码实现多处理,则代码会按预期生成两个进程,并由 pid 的打印输出记录。但是,每个进程都会打印“list2Get”(在 runGUIthread 中),然后就没有其他内容了。没有错误消息并且 python 代码似乎已经退出,因为系统活动监视器中没有列出持久进程。大概代码是“挂起”/在“window = tk.TK()”行退出,因为“print('type of window=',type(window))”行永远不会执行:
if __name__ == '__main__':
rand = random.Random()
testList2a = ['abc','def','geh']
testList2b = ['xyz', 'lmn', 'opq']
allLists = [testList2a,testList2b]
#runGUIthread(testList2a)
for list in allLists:
p = multiprocessing.Process(target=runGUIthread, args=(list,))
p.start()
ps = psutil.Process(p.pid)
print('pid = ', ps)
#with multiprocessing.Pool(processes=2) as pool:
# pool.map(runGUIthread, allLists)
我对多处理没有经验,所以也许我实现它不正确。我尝试使用 multiprocessing.Pool(),结果相同。 我无法找到表明 tkinter 无法在同一程序中生成多个 GUI 显示的信息。事实上,我发现有人意外生成了多个 GUI,尽管这似乎是 Python 3.8 使用 concurrent.futures.ProcessPoolExecutor (Concurrent.futures opens new windows in tkinter instead of running the function)。我目前使用的是 Python 3.7,并且希望不必重新安装新环境来使这个多处理代码工作,尽管这可能是必要的......?
其他信息:使用 python 3.7.6、tkinter 8.6.8、Eclipse 4.11.0、macOS10.13.6。
任何帮助表示赞赏。
【问题讨论】:
标签: python python-3.x multithreading tkinter multiprocessing