2015-07-25 12 views
5

Sto usando il modulo Python3 Asyncio per creare un'applicazione per il bilanciamento del carico. Ho due compiti IO pesanti:Asyncio due loop per diversi compiti di I/O?

  • modulo polling Uno SNMP, che determina il miglior server possibile
  • Un modulo "proxy-like", che bilancia le petizioni al server selezionato.

Entrambi i processi funzioneranno per sempre, sono indipendenti l'uno dall'altro e non dovrebbero essere bloccati dall'altro.

Non posso usare 1 ciclo di eventi perché si bloccherebbero a vicenda, c'è un modo per avere 2 loop di eventi o devo usare il multithreading/elaborazione?

Ho provato a utilizzare asyncio.new_event_loop() ma non è riuscito a farlo funzionare.

+0

Se progettato nel modo giusto, le coroutine di Asyncio non si bloccheranno a vicenda anche se girano sullo stesso loop. Asyncio passa in modo efficace avanti e indietro tra più coroutine/attività per dare l'effetto della concorrenza, anche se si utilizza un singolo thread. – shongololo

+0

@shongololo ma se ho un ciclo in esecuzione con "loop.run_forever()" blocca il ciclo e non posso fare altro se non lo interrompo. O sto sbagliando sbagliato? Questo è il comportamento che sto vedendo ... – brunoop

+0

non sono sicuro di comprendere appieno il dilemma. C'è qualcosa che ti impedisce di eseguire entrambi nello stesso ciclo? asyncio passerà automaticamente avanti e indietro (all'interno dello stesso ciclo) quando incontrerai i punti "yield from" all'interno del tuo codice. Questo è fondamentalmente il punto di asyncio, ti consente di eseguire più e potenzialmente bloccare le coroutine all'interno dello stesso ciclo senza che si blocchi l'altro. – shongololo

risposta

2

Asyncio ciclo di eventi è un singolo thread in esecuzione e non verrà eseguito nulla in parallelo, è come è stato progettato. La cosa più vicina a cui riesco a pensare è usare asyncio.wait.

from asyncio import coroutine 
import asyncio 

@coroutine 
def some_work(x, y): 
    print("Going to do some heavy work") 
    yield from asyncio.sleep(1.0) 
    print(x + y) 

@coroutine 
def some_other_work(x, y): 
    print("Going to do some other heavy work") 
    yield from asyncio.sleep(3.0) 
    print(x * y) 



if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(asyncio.wait([asyncio.async(some_work(3, 4)), 
          asyncio.async(some_other_work(3, 4))])) 
    loop.close() 

un modo alternativo è quello di utilizzare asyncio.gather() - restituisce un futuro risultati dalla lista data di futures.

tasks = [asyncio.Task(some_work(3, 4)), asyncio.Task(some_other_work(3, 4))] 
loop.run_until_complete(asyncio.gather(*tasks)) 
+0

So che i loop di eventi sono a thread singolo, ecco perché stavo chiedendo se ci sarebbe stato un modo per implementarlo usando 2 loop diversi. Non posso usare quel metodo perché, come ho detto, ogni coroutine sarà valida per sempre, non finirà. Cercherò di pubblicare la mia soluzione quando la capisco, grazie. – brunoop

+1

@brunoop È comunque possibile utilizzare questo approccio: non importa se le attività non terminano. Basta programmare le coroutine che ti servono usando 'asyncio.async (your_coroutine())', e poi chiama 'loop.run_forever()' una volta che sono state pianificate. Non è necessario utilizzare due thread. – dano

8

Rispondendo alla mia domanda di inviare la mia soluzione:

Quello che ho finito per fare è stato la creazione di un filo e un nuovo ciclo di eventi all'interno del filo per il modulo di polling, così ora tutti i moduli viene eseguito in un diverso ciclo continuo. Non è una soluzione perfetta, ma è l'unica che aveva senso per me (volevo evitare discussioni, ma dato che è solo una ...). Esempio:

import asyncio 
import threading 


def worker(): 
    second_loop = asyncio.new_event_loop() 
    execute_polling_coroutines_forever(second_loop) 
    return 

threads = [] 
t = threading.Thread(target=worker) 
threads.append(t) 
t.start() 

loop = asyncio.get_event_loop() 
execute_proxy_coroutines_forever(loop) 

Asyncio richiede che ogni ciclo esegua le sue coroutine nello stesso thread. Usando questo metodo si ha un ciclo foreach del ciclo degli eventi, e sono totalmente indipendenti: ogni ciclo eseguirà le sue coroutine sul proprio thread, quindi non è un problema. Come ho già detto, probabilmente non è la soluzione migliore, ma ha funzionato per me.

0

Se il server proxy è in esecuzione tutto il tempo, non può passare avanti e indietro. Il proxy ascolta le richieste dei client e le rende asincrone, ma l'altra attività non può essere eseguita, perché questa è pubblicata per sempre.

Se il proxy è una coroutine e sta morendo di fame il polling SNMP (non è mai in attesa), il cliente non chiede di rimanere affamato?

ogni coroutine verrà eseguito per sempre, essi non finiscono

Questo dovrebbe andare bene, a patto che lo fanno await/yield from. Anche lo echo server verrà eseguito per sempre, ma ciò non significa che non è possibile eseguire più server (su porte diverse) nello stesso ciclo.

0

Ma ho usato che, come questo, ma ancora la sua sincrono senza asincrona:

def main(*args):  
    loop = get_event_loop() 
    coro = asyncio.start_server(handle_echo, '127.0.0.1', 50008,loop=loop) 
    srv = loop.run_until_complete(coro)   
    loop.run_forever()  

@asyncio.coroutine 
def handle_echo(reader, writer): 
    data = yield from reader.read(500) 
    message = data.decode(encoding='utf-8')    

    nameindex=('name="calculator2"' in message) 
    if nameindex: 
     time.sleep(5) 
     writer.write("Content-Length: 1\r\n\r\n2".encode()) 
     yield from writer.drain() 
    else: 
     writer.write("Content-Length: 1\r\n\r\n1".encode()) 
     yield from writer.drain() 



    print("Close the client socket") 
    writer.close() 

se il valore ricevuto contiene (name = "calculator2") Aspetto per 5 secondi se non, basta rispondere e scrivere i dati subito. Ma quando lo collaudo, per prima cosa invia i dati al server con (nome = "calcolatrice2") e dati successivi senza (nome = "calcolatrice2"), ma i successivi dati maneggiano dopo 5 secondi di prima e dopo che il 2 ° dato sarà maneggiato.

suo sequenziale. cosa c'è di sbagliato in esso? e viceversa, come devo ottenere l'IP e la porta connessi al client?

Problemi correlati