2016-02-12 11 views
5

Penso che tutti sappiano cosa fare con le attività a lungo termine in django: usare il sedano e rilassarsi. Ma cosa succede se voglio ottenere benefici dalle websocket con aiohttp (o tornado)?Attività a esecuzione prolungata con server asincrono

Diciamo che ho un compito legato alla CPU che può richiedere da un paio di secondi a multipli (5-10) minuti. Sembra una buona idea gestire questa attività nel ciclo websocket e notificare all'utente i progressi. Nessuna richiesta Ajax, risposta molto rapida per compiti brevi.

async def websocket_handler(request): 
    ws = web.WebSocketResponse() 
    await ws.prepare(request) 

    async for msg in ws: 
     if msg.tp == aiohttp.MsgType.text:  
      answer_to_the_ultimate_question_of_life_the_universe_and_everything =\ 
       long_running_task(msg.data, NotificationHelper(ws)) 
      ws.send_str(json.dumps({ 
       'action': 'got-answer', 
       'data': answer_to_the_ultimate_question_of_life_the_universe_and_everything, 
      })) 
    return ws 

Ma d'altra parte, l'attività associata alla CPU servita in questo modo blocca l'intero thread come ho capito. Se ho 10 lavoratori e 11 clienti che vogliono usare l'applicazione, l'undicesimo client non verrà servito fino a quando non viene eseguita l'attività del primo client.

Forse, dovrei eseguire compiti che sembrano grandi nel sedano e compiti che sembrano piccole nel ciclo principale?

Quindi, la mia domanda: esiste un buon modello di progettazione per servire attività a esecuzione prolungata con server asincrono?

Grazie!

+0

'asyncio' non ti aiuterà con le attività legate alla CPU. – dirn

+0

@dirn è valido solo per attività legate all'IO e diversi tipi di interazione con il server? – dmitry

+1

Beh, asyncio può aiutare, è più vivace se l'attività è ospitata in un thread separato (o thread verde con rese o sottoprocesso per veramente viziosa). Ovvero, ci sono dubbi: che cosa è la connessione ws muore? Può esserci una corsa dati? Che dire "veramente più richieste di risorse" - 503/coda/blocco/errore? –

risposta

7

È sufficiente eseguire l'attività associata a CPU di vecchia data entro loop.run_in_executor() e inviare notifiche di avanzamento entro loop.call_soon_threadsafe().

Se il lavoro non è CPU ma è legato all'IO (ad esempio, l'invio di e-mail) è possibile creare una nuova attività tramite la chiamata loop.create_task(). Sembra che si generino nuove discussioni.

Se non è possibile utilizzare l'approccio fire-and-forget è necessario utilizzare il broker di messaggi persistenti come RabbitMQ (c'è la libreria https://github.com/benjamin-hodgson/asynqp per comunicare con Rabbit in modo asyncio).

Problemi correlati