Un'alternativa pulita e leggera al contorto di Python? [chiuso]


222

Qualche tempo fa ho scritto un web spider che ho multithread per consentire che si verifichino contemporaneamente richieste. Questo è accaduto nella mia giovinezza in Python, nei giorni prima che venissi a conoscenza del GIL e dei problemi associati che crea per il codice multithread (IE, il più delle volte le cose finiscono per serializzare!) ...

Vorrei rielaborare questo codice per renderlo più robusto e ottenere prestazioni migliori. Ci sono fondamentalmente due modi per farlo: potrei usare il nuovo modulo multiprocessore in 2.6+ o potrei scegliere un modello basato su reattore / evento di qualche tipo. Preferirei fare più tardi poiché è molto più semplice e meno soggetto a errori.

Quindi la domanda riguarda quale quadro sarebbe più adatto alle mie esigenze. Di seguito è riportato un elenco delle opzioni che conosco finora:

  • Twisted : Il nonno dei framework dei reattori Python: sembra complesso e un po 'gonfio. Ripida curva di apprendimento per un piccolo compito.
  • Eventlet : dai ragazzi di Lindenlab . Framework basato su Greenlet che è orientato verso questo tipo di attività. Ho dato un'occhiata al codice e non è troppo carino: non conforme a pep8, sparso con stampe (perché le persone lo fanno in un framework !?), API sembra un po 'incoerente.
  • PyEv : Immaturo, non sembra essere nessuno che lo sta usando in questo momento anche se è basato su libevent, quindi ha un solido backend.
  • asyncore : Da stdlib: über di basso livello, sembra un sacco di legwork coinvolti solo per ottenere qualcosa da terra.
  • tornado : sebbene si tratti di un prodotto orientato al server progettato per server di siti Web dinamici, presenta un client HTTP asincrono e un semplice ioloop . Sembra che potrebbe portare a termine il lavoro, ma non per quello a cui era destinato. [modifica: purtroppo non funziona su Windows, il che lo conta per me - è un requisito per me supportare questa piattaforma zoppa]

C'è qualcosa che mi è mancato per niente? Sicuramente ci deve essere una libreria là fuori che si adatta al punto debole di una libreria di rete asincrona semplificata!

[modifica: grande grazie a intgr per il suo puntatore a questa pagina . Se scorri verso il basso vedrai che c'è un elenco davvero bello di progetti che mirano ad affrontare questo compito in un modo o nell'altro. In realtà sembra che le cose siano effettivamente andate avanti sin dall'inizio di Twisted: le persone sembrano preferire una soluzione basata sulla routine comune piuttosto che una tradizionale orientata al reattore / callback. I vantaggi di questo approccio sono codici più chiari e diretti: sicuramente li ho trovati in passato, specialmente quando si lavora con boost.asioin C ++ quel codice basato sulla callback può portare a progetti che possono essere difficili da seguire e sono relativamente oscuri alla vista non allenata. L'uso di co-routine consente di scrivere un codice che sembri almeno un po 'più sincrono. Immagino che ora il mio compito sia capire quale di queste tante librerie mi piaccia guardare e provarci! Sono contento di averlo chiesto ora ...]

[modifica: forse di interesse per chiunque abbia seguito o inciampato su questa domanda o si preoccupi di questo argomento in qualsiasi senso: ho trovato un ottimo resoconto dello stato attuale degli strumenti disponibili per questo lavoro]


14
Python è multithread, semplicemente non consente a due thread di eseguire contemporaneamente il codice Python.
intgr,

86
Ho imparato molto di più dalla tua domanda che dalle risposte ad essa.
Denis Otkidach,

2
@Denis: eh, grazie credo! Ci sono stati anche alcuni buoni suggerimenti nelle risposte, in particolare intgr's. Conoscevo un sacco di opzioni là fuori e non volevo solo che le risposte fossero piene di quelle, quindi ho pensato di andare al problema di
svelare

5
> le persone sembrano preferire una soluzione basata sulla co-routine piuttosto che una tradizionale orientata al reattore / callback Questo non è un confronto ragionevole. Le "soluzioni basate sulla routine" e le soluzioni "orientate al reattore" sono ortogonali. (Ignorando il fatto che Python non ha coroutine) Dai un'occhiata ai callback inline di Twisted per vedere come puoi avere lo stile di programmazione che preferisci con un livello di rete robusto e maturo che non ti esporrà a complesse idiosincrasie della piattaforma.
Jean-Paul Calderone,

2
Alcuni punti da aggiungere: 1. Tornado funziona molto bene su Windows. Non è altrettanto performante e scalabile perché utilizza selectper il multiplexing I / O. Ma dovresti essere in grado di ottenere prestazioni decenti con il tornado-pyuv . 2. Ora c'è asyncio in Python 3.3+ e il suo backport trollius che consente di eseguire qualsiasi applicazione Tornado nel suo loop di eventi (Twisted sarà presto supportato).
schlamar,

Risposte:


28

Mi è piaciuto il modulo Python in concomitanza che si basa su microthreads Stackless Python o Greenlet per un thread leggero. Tutti gli I / O di rete bloccanti sono resi in modo trasparente asincrono attraverso un singolo libeventloop, quindi dovrebbe essere quasi efficiente come un vero server asincrono.

Suppongo che sia simile a Eventlet in questo modo.

Il rovescio della medaglia è che la sua API è abbastanza diversa dai sockets/ threadingmoduli di Python ; devi riscrivere un bel po 'della tua applicazione (o scrivere un layer shim di compatibilità)

Modifica: sembra che ci sia anche cogen , che è simile, ma usa i generatori potenziati di Python 2.5 per le sue coroutine, invece di Greenlets. Ciò lo rende più portatile della concorrenza e di altre alternative. L'I / O di rete viene eseguito direttamente con epoll / kqueue / iocp.


@intgr: ottimi collegamenti. Avevo già visto entrambi quelli una volta, quelli erano i tipi di cose che speravo di vedere svuotati. +1
jkp

3
Sembra che la concorrenza sia un progetto morto con il loro essere l'ultimo aggiornamento quattro anni fa.
Gewthen,

il progetto è morto, così anche Hyves!
Bahadir Cambel,

1
Sono successe molte cose da Python 2.5. asyncio in Python 3.5 è fantastico.
Joseph Sheedy,

99

Twisted è complesso, hai ragione. Contorto non è gonfio.

Se dai un'occhiata qui: http://twistedmatrix.com/trac/browser/trunk/twisted troverai una suite organizzata, completa e molto ben testata di molti protocolli di Internet, oltre a un codice helper per scrivere e distribuire applicazioni di rete molto sofisticate. Non confonderei il gonfiore con la completezza.

È noto che la documentazione di Twisted non è la più intuitiva a prima vista, e credo che questo allontani un numero sfortunato di persone. Ma Twisted è fantastico (IMHO) se ci metti il ​​tempo. L'ho fatto e ne è valsa la pena, e consiglierei ad altri di provare lo stesso.


4
@clemesha: forse hai ragione, e non è sovraccarico, ma sembra che ci sia un po 'troppo per farmi girare la testa per fare qualcosa di semplice. Capisco la programmazione asincrona, ho lavorato in C ++ con boost :: asio, quindi i concetti non sono nuovi, ma è tutto il gumph che si comporta nel fare cose contorte: è un mondo completamente nuovo, proprio come il django è per le cose sul web. Ancora una volta, quando lavoro su Web, lavoro con un codice WSGI leggero e collego solo ciò di cui ho bisogno. Cavalli per corsi credo.
jkp,

7
@clemesha: erm, oggi ho fatto il grande passo per dare un'occhiata: contorto pesa 20 MB! Anche il nucleo è di 12 MB .... se non è gonfio, non sono sicuro di cosa sia.
jkp,

29
Le API Twisted di base sono piuttosto piccole (reattore, differito, protocollo). La maggior parte del codice Twisted è implementazioni di protocollo asincrono che utilizzano queste basi. "Bloat" non è un aggettivo utile qui (o addirittura nella maggior parte dei casi). Le dimensioni di Twisted sono ragionevoli per la quantità di roba che fa.
daf

56

gevent viene ripulito da eventlet .

Per quanto riguarda le API, segue le stesse convenzioni della libreria standard (in particolare i moduli di threading e multiprocessing) in cui ha senso. Quindi hai cose familiari come Queue ed Event con cui lavorare.

Supporta solo libevent ( aggiornamento: libev dal 1.0 ) come implementazione del reattore ma ne sfrutta appieno, con un server WSGI veloce basato su libevent-http e risoluzione di query DNS tramite libevent-dns invece di usare un pool di thread come la maggior parte delle altre librerie fare. ( aggiornamento: poiché 1.0 c-ares viene utilizzato per eseguire query DNS asincrone; threadpool è anche un'opzione.)

Come eventlet, rende inutili callback e differiti utilizzando greenlet .

Guarda gli esempi: download simultaneo di più URL , webchat di polling lungo .


4
Secondo, gevent - Dopo aver esaminato molte delle soluzioni, gevent ha funzionato molto bene per me. Mi ha permesso di conservare la parte migliore del mio programma esistente e le modifiche richieste erano banali - Soprattutto, se il codice deve essere mantenuto in 3, 4, 5, ... anni, fa ancora senso per chiunque non abbia familiarità con gevent, il più grande showtopper per Twisted è la forte curva di apprendimento, questo causa problemi non solo durante l'implementazione, ma anche più in basso durante la manutenzione ...
Martin Tournoij

27

Un confronto davvero interessante di tali framework è stato compilato da Nicholas Piël sul suo blog: vale la pena leggerlo!


2
Mentre sono d'accordo sul fatto che l'articolo sia stato una lettura interessante, penso che valga la pena considerare la validità dei parametri di riferimento presentati. Vedi i commenti qui: reddit.com/r/programming/comments/ahepg/…
clemesha

1
@clemesha, mentre vale la pena notare il punto in quella pagina reddit, il benchmark è stato fatto su una macchina dual core e probabilmente non soffriva del difetto fatale descritto. Suppongo che sia possibile sia il client e server di corse sullo stesso nucleo, ma non sembra probabile.
Peter Hansen,

15

Nessuna di queste soluzioni eviterà il fatto che GIL prevenga il parallelismo della CPU: sono solo modi migliori per ottenere il parallelismo IO che hai già con i thread. Se pensi di poter fare un IO migliore, segui sicuramente uno di questi, ma se il tuo collo di bottiglia è in fase di elaborazione dei risultati, nulla qui aiuterà se non per il modulo multiprocessore.


Cosa c'è di sbagliato nell'utilizzo di più processi?
Emil Ivanov,

3
Niente affatto, quindi il suggerimento di utilizzare il modulo multiprocessing.
Adam Hupp,

11

Non vorrei andare fino a chiamare Twisted gonfio, ma è difficile avvolgere la testa. Ho evitato di accontentarmi di imparare per un po ', dato che ho sempre desiderato qualcosa di più semplice per i "piccoli compiti".

Tuttavia, ora che ci ho lavorato un po 'di più, devo dire che avere tutte le batterie incluse è MOLTO bello.

Tutte le altre librerie asincrone con cui ho lavorato sono molto meno mature di quanto non appaiano. Il loop degli eventi di Twisted è solido.

Non sono sicuro di come risolvere la ripida curva di apprendimento attorcigliata. Potrebbe essere utile se qualcuno lo rovinasse e pulisse un po 'di cose, come rimuovere tutta l'innesto di compatibilità retroattiva e i progetti morti. Ma questa è la natura del software maturo, suppongo.


Se hai mai cercato come viene implementato il reattore GTK su Windows (polling hardcore ogni 10 ms: twistedmatrix.com/trac/browser/trunk/twisted/internet/… ), non lo chiameresti "maturo" ...
schlamar

2
Ciao @schlamar. Questo brutto hack è stato implementato come soluzione alternativa per alcuni bug piuttosto gravi in ​​GTK +, ai tempi in cui c'era molta meno preoccupazione per l'efficienza energetica :). Ma la bellezza di Twisted è che possiamo avere questo bug una volta , risolverlo nel framework e i nostri utenti non devono preoccuparsene. Vorresti contribuire con una soluzione che risolve questo problema e ne elimina (deprecati e poi rimuove) PortableGtkReactor?
Glifo

1
@Glyph Ho aggiunto consigli utili su twistedmatrix.com/trac/ticket/4744#comment:2 se qualcun altro vuole affrontare questo problema, perché alcuni di questi problemi esistono ancora. A proposito, avresti potuto risolvere questo problema in modo molto più efficiente pianificando i callback tra i due loop di eventi.
schlamar,

7

Kamaelia non è ancora stata menzionata. Il suo modello di concorrenza si basa sul cablaggio di componenti insieme al messaggio che passa tra le caselle di posta in entrata e quelle in uscita. Ecco una breve panoramica.


5
Ho usato kamaelia per un'app: è stato estremamente doloroso. IMHO ci sono altre, migliori opzioni per concurrenct in python (la maggior parte delle quali sono menzionate sopra)
Ben Ford

7

Ho iniziato a usare il twisted per alcune cose. Il bello è quasi perché è "gonfio". Ci sono connettori per quasi tutti i protocolli principali là fuori. Puoi avere un jabber bot che prenderà i comandi e pubblicherà su un server irc, li invierà via email a qualcuno, eseguirà un comando, leggerà da un server NNTP e monitorerà una pagina web per le modifiche. La cattiva notizia è che può fare tutto ciò e può rendere le cose eccessivamente complesse per compiti semplici come spiegato dall'OP. Il vantaggio di Python è che includi solo ciò di cui hai bisogno. Quindi, mentre il download può essere 20 MB, è possibile includere solo 2 MB di librerie (che è ancora molto). La mia più grande lamentela con twisted è sebbene includano esempi, qualsiasi cosa al di fuori di un semplice server tcp sei da solo.

Pur non essendo una soluzione Python, ho visto node.js guadagnare molto più trazione negli ultimi tempi. In effetti ho pensato di cercarlo per progetti più piccoli, ma mi sento solo rabbrividire quando sento javascript :)


Sono un grande fan di Python. - Dai un'occhiata a "Javascript - Le parti buone" di Douglas Crockford (3, 4 video). E sbirciatina a CoffeeScript. Si scopre che JS ha cose che Python dovrebbe avere, tranne la Sintassi, ahah. CS ha cercato di mitigarlo, ma è un po 'maldestro su questo ...
Robert Siemer

4

C'è un buon libro sull'argomento: "Twisted Network Programming Essentials", di Abe Fettig. Gli esempi mostrano come scrivere molto codice Pythonic e, a me personalmente, non mi sembrano basati su un framework gonfio. Guarda le soluzioni nel libro, se non sono pulite, allora non so cosa significhi pulito.

Il mio unico enigma è lo stesso che ho con altri framework, come Ruby. Mi preoccupo, si ingrandisce? Odierei affidare un client a un framework che avrà problemi di scalabilità.


4

Whizzer è un piccolo framework socket asincrono che utilizza Pyev. È molto veloce, principalmente a causa del pyev. Tenta di fornire un'interfaccia simile come contorta con alcune lievi modifiche.


2

Prova anche Syncless . È basato sul coroutine (quindi è simile a Concurrence, Eventlet e gevent). Implementa sostituzioni drop-in non bloccanti per socket.socket, socket.gethostbyname (ecc.), Ssl.SSLSocket, time.sleep e select.select. È veloce. Ha bisogno di Stackless Python e libevent. Contiene un'estensione obbligatoria di Python scritta in C (Pyrex / Cython).


2

Confermo la bontà della sincerità . Può usare libev (la versione più recente, più pulita e con prestazioni migliori di libevent). Alcune volte fa non ha tanto supporto quanto libevent, ma ora il processo di sviluppo va oltre ed è molto utile.



0

Ti invitiamo a dare un'occhiata a PyWorks, che ha un approccio alquanto diverso. Consente l'esecuzione di istanze di oggetto nel proprio thread e rende asincrone le chiamate di funzione a quell'oggetto.

Lascia che una classe erediti da Task anziché da oggetto ed è asincrona, tutte le chiamate dei metodi sono Proxy. I valori di ritorno (se necessari) sono proxy futuri.

res = obj.method( args )
# code continues here without waiting for method to finish
do_something_else( )
print "Result = %d" % res # Code will block here, if res not calculated yet

PyWorks è disponibile su http://bitbucket.org/raindog/pyworks


1
Anche se questo è interessante e potrebbe essere adatto per alcune attività, l'uso dei thread per il networking funziona male (specialmente su Python a causa del GIL). E questa era esattamente la domanda: un framework evented o con multiprocessing. Quindi la tua risposta è chiaramente fuori portata ...
schlamar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.