[Python] Non blocking http server e integrazione con database relazionali

Manlio Perillo manlio.perillo a gmail.com
Ven 14 Mar 2014 18:12:15 CET


2014-03-13 19:35 GMT+01:00 Balan Victor <balan.victor0 a gmail.com>:

> Di recente ho letto un po di tornado, e in particolare mi sono soffermato
> sul modulo tornado.httpserver(Non-blocking HTTP server). Stando a quello
> che c'è scritto sulla documentazione ufficiale parla di "non-blocking,
> single-threaded HTTP server" e di risolvere il problemi di tipo C10K. Qua
> sembra interessante, anche se non ho la minima idea di come funzioni.
>
> [...]

> Detto questo, non riesco a capire l'utilità di un HTTP Server con
> performance elevatissime ma che non permetta una minima interazione con il
> database.
>
> Probabilmente sopra ho scritto delle cavolate ma mi mancano completamente
> le basi per questo tipo di argomenti e volevo capire meglio come funzionano
> e quali sono i campi di applicazione di tecnologie simili.
>
>
L'argomento è complesso.
Nel caso di un server C10K ready ci sono due aspetti principali.
Il primo riguarda tutto quel codice che esegue una richiesta ed aspetta una
risposta.
Il secondo riguarda il paradigma utilizzato per gestire il flusso del
codice.

Il 97.7% delle librerie disponibili fa qualcosa del tipo:

  >>> status = send_request(data)
  >>> resp = recv_response()

Entrambe le funzioni potrebbero metterci molto tempo a completare, ma
questo codice blocca l'intero thread fino a quando resp non è disponibile.

Quello che fa tornado è di usare quelle che si chiamano coroutine, o
threading cooperativo.
In questo caso sia send_request che recv_response bloccano il flusso
corrente del codice (la coroutine corrente), ma non l'intero thread perchè
usando le coroutine viene effettuato un salto (simile al goto) che va ad
eseguire altre funzioni coroutine.

Senza le coroutine, quello che si fa è usare le callback ed una macchina a
stati (lo stato deve essere gestito manualmente perchè non hai lo stack
disponibile nel codice "normale").

L'esempio di prima diventa:

  >>> def do_request(data, ctx):
  >>>     send_request(data, on_request_done, ctx)
  >>>
  >>> def on_request_done(status, ctx):
  >>>      recv_response(on_response_done, ctx)
  >>>
  >>> def on_response_done(resp, ctx):
  >>>     # DONE

Come vedi diventa molto complicato, specialmente se ad esempio devi fare il
parsing di un protocollo come HTTP (puoi vedere il codice di Twisted se ti
interessa).

Tra l'altro il motivo perchè tornado va di moda è perchè permette di avere
il codice che è praticamente lo stesso di quello "normale", ma che si
comporta in modo completamente diverso.  Twisted offre un framework per la
programmazione asincrona da anni, ma non è mai stato di moda, perchè molto
più difficile.

Considerato tutti i problemi che gli utenti hanno con tornado e friends (e
che nemmeno sanno di sapere), direi che, come sempre, "explicit is better
than implicit".

Il mio suggerimento è sempre quello di imparare prima le basi (vicino a
quello che realmente succede) e solo dopo utilizzare cose che rendono la
programmazione e manutenzione più semplice.

Come ultima cosa: gevent (l'implementazione delle coroutine) sembra risolva
tutti i problemi, ma in realtà tutto quello che fa ha un costo.  Non è un
caso che i web server C10K usano la programmazione tramite callback e
macchina a stati; questo perchè è molto più efficiente nella gestione della
memoria.  Ogni coroutine è come un thread ed ha bisogno di memoria per lo
stack, oltre poi al costo per il context switch.


Ciao  Manlio
-------------- parte successiva --------------
Un allegato HTML è stato rimosso...
URL: <http://lists.python.it/pipermail/python/attachments/20140314/1fb4ba42/attachment-0001.html>


Maggiori informazioni sulla lista Python