2015-04-21 30 views
7

Sto lavorando su una semplice applicazione di rete grafica, utilizzando asyncio e tkinter. Sto incontrando il problema di combinare il ciclo di eventi asyncio con il mainloop di Tk. Se possibile, mi piacerebbe farlo senza discussioni, perché entrambe queste librerie (ma specialmente tkinter) non sono molto thread-safe. Attualmente, sto usando Tk.update in un coroutine asyncio, che gestisce una sola iterazione del ciclo di eventi tk:È possibile eseguire solo un singolo passaggio del ciclo di eventi asyncio

@asyncio.coroutine 
def run_tk(tk, interval=0.1): 
    try: 
     while True: 
      tk.update() 
      yield from asyncio.sleep(interval) 
    except TclError as e: 
     if "application has been destroyed" not in e.args[0]: 
      raise 

Tuttavia, nell'interesse di esplorare tutte le opzioni, mi chiedevo se era possibile per fare il contrario - se fosse possibile invocare solo una singola iterazione di un ciclo di eventi asyncio all'interno di un callback tk.

+0

È possibile [combinare il ciclo principale Tk con asyncio] (https://github.com/python/asyncio/issues/ 21), ma non so se questo permetta ancora di elaborare il traffico di rete (cioè come gli eventi di rete fluiscono nel ciclo principale di Tk)? –

+0

Sembra che funzioni, ma imbroglia. Crea un TkEventLoop, che esegue essenzialmente 'update' in un ciclo, ma crea anche un ciclo di eventi tradizionale per eseguire i/o di rete e eseguirlo in un thread. È il peggiore di entrambi i mondi; l'unico vantaggio è che i callback diretti ('loop.call_later') sono richiamati direttamente nel ciclo di eventi di Tk. – Lucretiel

+0

Mi manca un esempio di lavoro minimo nella domanda e nelle risposte. – buhtz

risposta

9

La mancanza di metodo pubblico come loop.run_once() è intenzionale. Non tutti gli eventi supportati hanno un metodo per iterare un passo. Spesso l'API sottostante ha metodi per la creazione di eventi loop e l'esecuzione per sempre ma l'emulazione di un singolo passaggio può essere molto inefficace.

Se si ha realmente bisogno è possibile implementare single-step di iterazione facile:

import asyncio 


def run_once(loop): 
    loop.call_soon(loop.stop) 
    loop.run_forever() 


loop = asyncio.get_event_loop() 

for i in range(100): 
    print('Iteration', i) 
    run_once(loop) 
+0

aspetta ... cosa? Come fa 'run_forever' eseguire solo una volta? Come può aver senso questo? – vitiral

+1

@cloudformdesign Vedere la mia risposta [qui] (http://stackoverflow.com/a/29868627/2073595) per una spiegazione. – dano

+0

e quella era la mia domanda! Grazie! – vitiral