我玩弄Pipe和Process從multiprocessing模塊(Python的3.8)。我的初始程式如下所示:
from multiprocessing import Process, Pipe
class Process1(object):
def __init__(self, pipe_out):
self.pipe_out = pipe_out
self.run()
def run(self):
try:
while True:
print("Sending message to process 2")
self.pipe_out.send(["hello"])
except KeyboardInterrupt:
pass
class Process2(object):
def __init__(self, pipe_in):
self.pipe_in = pipe_in
self.run()
def run(self):
try:
while self.pipe_in.poll():
request = self.pipe_in.recv()
method = request[0]
args = request[1:]
try:
getattr(self, method "_callback")(*args)
except AttributeError as ae:
print("Unknown callback received from pipe", str(ae))
print("Process 2 done with receiving")
except KeyboardInterrupt:
pass
def hello_callback(self):
print("Process 1 said hello")
class Controller(object):
def __init__(self):
pipe_proc1_out, pipe_proc2_in = Pipe()
self.proc1 = Process(
target=Process1,
args=(pipe_proc1_out, )
)
self.proc2 = Process(
target=Process2,
args=(pipe_proc2_in, )
)
def run(self):
try:
self.proc1.start()
self.proc2.start()
while True:
continue
except KeyboardInterrupt:
print("Quitting processes...")
self.proc1.join(1)
if self.proc1.is_alive():
self.proc1.terminate()
self.proc2.join(1)
if self.proc2.is_alive():
self.proc2.terminate()
print("Finished")
def pipes():
c = Controller()
c.run()
if __name__ == "__main__":
pipes()
我有一個Controller運行直到收到鍵盤中斷的實體。它還處理兩個行程Process1,Process2前者不斷發送,后者不斷接收。
上面的代碼是涉及復雜 GUI (PySide)、影像處理 (OpenCV) 和游戲引擎 (Panda3D) 的更大任務的骨架。所以我嘗試添加 Tkinter 作為 GUI 示例:
from multiprocessing import Process, Pipe
import tkinter as tk
class Process1(tk.Frame):
def __init__(self, pipe_out):
self.pipe_out = pipe_out
self.setup_gui()
self.run()
def setup_gui(self):
self.app = tk.Tk()
lb1 = tk.Label(self.app, text="Message:")
lb1.pack()
self.ent1 = tk.Entry(self.app)
self.ent1.pack()
btn1 = tk.Button(self.app, text="Say hello to other process",
command=self.btn1_clicked)
btn1.pack()
def btn1_clicked(self):
msg = self.ent1.get()
self.pipe_out.send(["hello", msg])
def run(self):
try:
self.app.mainloop()
except KeyboardInterrupt:
pass
class Process2(object):
def __init__(self, pipe_in):
self.pipe_in = pipe_in
self.run()
def run(self):
try:
while self.pipe_in.poll():
request = self.pipe_in.recv()
method = request[0]
args = request[1:]
try:
getattr(self, method "_callback")(*args)
except AttributeError as ae:
print("Unknown callback received from pipe", str(ae))
print("Process 2 done with receiving")
except KeyboardInterrupt:
pass
def hello_callback(self, msg):
print("Process 1 say\"" msg "\"")
class Controller(object):
def __init__(self):
pipe_proc1_out, pipe_proc2_in = Pipe()
self.proc1 = Process(
target=Process1,
args=(pipe_proc1_out, )
)
self.proc2 = Process(
target=Process2,
args=(pipe_proc2_in, )
)
def run(self):
try:
self.proc1.start()
self.proc2.start()
while True:
continue
except KeyboardInterrupt:
print("Quitting processes...")
self.proc1.join(1)
if self.proc1.is_alive():
self.proc1.terminate()
self.proc2.join(1)
if self.proc2.is_alive():
self.proc2.terminate()
print("Finished")
def pipes():
c = Controller()
c.run()
if __name__ == "__main__":
pipes()
請注意,當前 Tkinter 視窗只能在“父”行程通過鍵盤中斷時才能關閉。
每當我單擊按鈕并呼叫按鈕的命令時,我的程式都會進入錯誤狀態并顯示以下訊息:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\USER\Anaconda3\envs\THS\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\USER\PycharmProjects\PythonPlayground\pipes_advanced.py", line 26, in btn1_clicked
self.pipe_out.send(["hello", 1, 2])
File "C:\Users\USER\Anaconda3\envs\THS\lib\multiprocessing\connection.py", line 206, in send
self._send_bytes(_ForkingPickler.dumps(obj))
File "C:\Users\USER\Anaconda3\envs\THS\lib\multiprocessing\connection.py", line 280, in _send_bytes
ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True)
BrokenPipeError: [WinError 232] The pipe is being closed
起初我認為問題在于我從Entry.get()電話中收到的價值(我的 Tkinter 技能生疏了)。我列印msg并從小部件中獲取了文本。
接下來我嘗試將一個常量字串作為我通過管道發送的引數的值:
def btn1_clicked(self):
self.pipe_out.send(["hello", "world"])
出現了同樣的錯誤。捕獲例外BrokenPipeError對我沒有任何好處(除非我想在管道損壞的情況下處理這種情況)。
如果我對程式的第一個版本(沒有 Tkinter)做同樣的事情,它就可以作業。這讓我相信我的問題來自于我集成 Tkinter 的方式。
uj5u.com熱心網友回復:
您遇到的問題是您輪詢管道,但檔案說:
民意調查([超時])
回傳是否有任何資料可供讀取。
如果未指定超時,則它將立即回傳。
在第一個示例中,它起作用是因為在啟動時Process1您立即將資料發送到管道:
def run(self):
try:
while True:
print("Sending message to process 2")
self.pipe_out.send(["hello"])
except KeyboardInterrupt:
pass
并且您連續執行此操作,因此.poll將回傳True并且回圈Process2將繼續。
由于tkinter沒有任何東西立即發送到管道,它等待用戶單擊一個按鈕,當任何一個可能發生時,Process2已經呼叫poll并立即回傳False并且它甚至沒有啟動該回圈。如果您注意到,那么它也幾乎立即在終端中列印
“處理2完成接收”
要解決這個問題,似乎最簡單的方法是使用
while self.pipe_in.poll(None):
每個檔案意味著
“如果超時為 None,則使用無限超時。”
對于像用戶界面這樣的東西,這似乎是最合適的(至少從用戶的角度來看(或者我認為))所以基本上你的run方法Process2應該是這樣的:
def run(self):
try:
while self.pipe_in.poll(None):
request = self.pipe_in.recv()
method = request[0]
args = request[1:]
try:
getattr(self, method "_callback")(*args)
except AttributeError as ae:
print("Unknown callback received from pipe", str(ae))
print("Process 2 done with receiving")
except (KeyboardInterrupt, EOFError):
pass
也與問題無關,但似乎不需要從tk.Framein Process1(或objectin Process2(除非您確實需要使其與 Python2 兼容)),您幾乎可以繼承 from tk.Tk,這應該更容易實際使用它作為主視窗因為self將是Tk實體
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/356583.html
標籤:Python 特金特 多处理 管道 python-多处理
下一篇:用于多處理的tkinter進度條
