Le finestre di TKinter non vengono visualizzate quando si utilizza il multiprocessing su Linux
-
03-07-2019 - |
Domanda
Voglio generare un altro processo per visualizzare un messaggio di errore in modo asincrono mentre il resto dell'applicazione continua.
Sto usando il modulo multiprocessing
in Python 2.6 per creare il processo e sto provando a visualizzare la finestra con TKinter
.
Questo codice ha funzionato bene su Windows, ma eseguendolo su Linux la finestra TKinter
non appare se chiamo 'showerror (" Errore MyApp " ;, " Si è verificato qualcosa di brutto. " ;) '
. appare se lo eseguo nello stesso processo chiamando direttamente showerrorprocess
. Detto questo, sembra che TKinter
funzioni correttamente. Posso stampare sulla console e fare altre cose dai processi generati da multiprocessing
, quindi sembra funzionare anche.
Sembra che non funzionino insieme. Devo fare qualcosa di speciale per consentire ai sottoprocessi generati di creare finestre?
from multiprocessing import Process
from Tkinter import Tk, Text, END, BOTH, DISABLED
import sys
import traceback
def showerrorprocess(title,text):
"""Pop up a window with the given title and text. The
text will be selectable (so you can copy it to the
clipboard) but not editable. Returns when the
window is closed."""
root = Tk()
root.title(title)
text_box = Text(root,width=80,height=15)
text_box.pack(fill=BOTH)
text_box.insert(END,text)
text_box.config(state=DISABLED)
def quit():
root.destroy()
root.quit()
root.protocol("WM_DELETE_WINDOW", quit)
root.mainloop()
def showerror(title,text):
"""Pop up a window with the given title and text. The
text will be selectable (so you can copy it to the
clipboard) but not editable. Runs asynchronously in
a new child process."""
process = Process(target=showerrorprocess,args=(title,text))
process.start()
Modifica
Il problema sembra essere che TKinter
è stato importato dal processo padre e "ereditato" nel processo figlio, ma in qualche modo il suo stato è indissolubilmente legato al processo genitore e non può funzionare nel bambino. Fintanto che ti assicuri di non importare TKinter
prima di generare il processo figlio, funzionerà perché allora è il processo figlio che lo importa per la prima volta.
Soluzione
Questa discussione potrebbe essere utile.
Ecco alcuni problemi di esempio che ho riscontrato:
Mentre il modulo multiprocessing segue da vicino il threading, non è sicuramente una corrispondenza esatta. Un esempio: poiché i parametri a il processo deve essere selezionabile , ho dovuto passare molto codice modifiche per evitare il passaggio di oggetti
Tkinter
poiché non lo sono pickleable . Ciò non si verifica con il modulo di threading.
process.terminate ()
non funziona davvero dopo il primo tentativo. Il secondo o terzo tentativo semplicemente blocca l'interprete, probabilmente perché le strutture dei dati sono danneggiate (menzionate nell'API, ma questo è poca consolazione).
Altri suggerimenti
Forse chiamando il comando shell xhost +
prima di chiamare il tuo programma da quella stessa shell funzionerà?
Suppongo che il tuo problema risieda nell'X-server.