Progettazione di un "servizio" Python usando multiprocessing e threading

0

A causa del Global Interpreter Lock, il multithreading in Python non influisce sul parallelismo. Questa limitazione viene evitata nella libreria multiprocessing generando invece nuovi processi. Ma il threading migliora la reattività in determinate situazioni (legate all'IO). (da questa risposta su SO).

La mia situazione è la seguente. Viene comunicato un processo Python utilizzando stdin e stdout . Una riga corrisponde a un messaggio e viene soddisfatta con una riga di risultato. Attualmente ho un singolo processo che consuma i messaggi uno per uno e produce un risultato. Tuttavia, l'elaborazione implica calcoli moderatamente pesanti, pertanto è possibile ottenere prestazioni migliori con calcoli paralleli di richieste diverse.

Dopo aver letto le differenze e gli usi del threading e del multiprocessing, ho trovato una struttura che si spera possa soddisfare questo compito.

  • I messaggi dovrebbero essere gestiti in modo asincrono per consentire la lettura dello stdin e la distribuzione del lavoro prima di restituire i risultati. Due thread potrebbero essere generati per gestire la lettura e la scrittura.
  • È possibile generare più processi per rispondere a tali richieste. Un esempio della documentazione multiprocessing : qui (# 3: utilizzo delle code)

Come l'esempio higlights (con tempi di sospensione casuali), l'ordine di risposta non è fisso. I lavori vengono restituiti nell'ordine in cui sono terminati.

È un design sensato? Inoltre, cosa si potrebbe fare per preservare l'ordine dei messaggi nella pipeline?

    
posta Felix 01.08.2018 - 15:46
fonte

2 risposte

1

Sì. L'ho implementato un paio di volte con successo.

Quello che ho fatto è stato:

  • Crea un'applicazione python del servizio di utilità che legge un messaggio JSON, esegue un calcolo e stampa una risposta. (questo è lento ma facile da eseguire il debug / test).
  • Implementare un leggero miglioramento su quel processo, in modo che lo script python (chiamato) del servizio continui a leggere da stdin e processare i record fino a quando non arriva a EOF (salvando tutto il tempo di avvio del servizio) - questo rende le cose molto più veloci. / li>
  • Quindi implementa un argomento OPTIONAL per il servizio --binary - in modo che possa essere eseguito con gli input binarizzati (se chiamati con --binary) o con gli input di testo in attesa (JSON) predefiniti.
  • Infine, nel livello chiamante, puoi generare tutti i processi di computazione back-end che desideri (ne ho fatto uno per core del sistema per far funzionare la CPU del dispositivo caldo).

Con tutto questo - insieme, hai un'architettura molto semplice, testabile (myPythonApp.py < test.json), che funziona tanto quanto Python può (quindi non eccezionale ;-)). Ma - è ANCHE un'architettura in cui puoi CHIAMARLO da qualsiasi sistema linguistico desideri, e se hai bisogno di eseguire tutto più velocemente, puoi RIPRISCRIVERE il servizio Python back-end in C ++ (e testarlo facilmente ottiene gli stessi risultati di Python esistente ma più veloce).

    
risposta data 01.08.2018 - 16:16
fonte
0

Poiché le risposte devono essere nello stesso ordine delle richieste, l'utilizzo di più processi non accelera le singole risposte: è comunque necessario attendere fino al completamento di tutte le richieste precedenti. Ma ora puoi elaborare più richieste contemporaneamente. Poi:

  • il tempo di attesa fino all'avvio del lavoro su una richiesta potrebbe essere ridotto
  • il throughput del sistema è aumentato

Non tenere una coda di richieste che vengono consumate da un pool di lavoratori. Invece, mantieni una coda di lavoratori in sospeso. È quindi possibile attendere fino a quando il primo operatore in linea ha prodotto una risposta. Questo rende più facile tenere traccia dell'ordine.

Invece di gestire autonomamente pool e code di worker, considera se è possibile utilizzare Python 3.6+ asyncio. Ciò consente di utilizzare facilmente un pool di processi anziché un pool di thread e di estrarre molti dettagli. Inoltre, sarai in grado di utilizzare i future per rappresentare i risultati dei lavoratori in sospeso. Quindi semplicemente await il prossimo futuro, nell'ordine in cui hai creato questi futures.

    
risposta data 01.08.2018 - 16:14
fonte

Leggi altre domande sui tag