[Python] Estendere Python in Go (era: Re: Parere su Go di un professore di informatica (delle superiori) nonche' uno dei fondatori di ERLUG)

enrico franchi enrico.franchi a gmail.com
Mer 26 Ago 2015 16:20:45 CEST


2015-08-26 14:39 GMT+01:00 Carlos Catucci <carlos.catucci a gmail.com>:

>
> Enrico il problema e' sempre di unita' di misura. Il progetto piu' piccolo
> a cui lavori tu e di qualche "anno luce" piu' grande del piu' grande a cui
> lavoro io.
>

Ma non e' questo il problema... spiego meglio.


> Per me impiegare tempo ad apprendere come fare in Go le cose che faccio
> con Python e Django/Flask e' una "spesa" che non posso affrontare ora.
>

E questo e' chiaro (in realta' lo e' per tutti).


> Pero' se mi trovo (come potrei se il progetto a cui sto lavorando vede la
> luce) a dover fare cose che in Python non "vengono bene", esempio gestire
> qualche migliaio di messaggi "conteporanei" provenienti da altrettanti
> router sparsi qua e la, ecco che una routine Go, meglio se wrappabile, mi
> puo' risolvere la cosa senza che io debba impazzire.
>

E io quello che ti sto dicendo e' che a fare questo il "supermetodo"
ficcato nell'infrastruttura Python esistente non e' una buona idea.

Allora, parliamo della tua infrastruttura attuale. Hai un db in cui scrivi
e da cui leggi. Avrai una webapp che legge dal db per "vedere cose". Dopo
di che hai bisogno di un coso che riesca a ricevere molte scritture e le
metta nel db. Da quello che ho capito, la lettura non e' un problema
veramente critico (relativamente pochi operatori dovranno leggere i dati,
immagino tramite pagine web). Il problema e' l'ingestion dei dati.

Quindi lasciamo completamente perdere la webapp per leggere (che stara' in
Python e tanti saluti). Tu devi progettare un coso veloce che prende,
immagino delle gran POST (o PUT) e ficca dati corrispondenti nel DB. Ora,
cosa succede ad una put?

Avrai immagino un loadbalancer di qualche tipo (o reverse proxy che dir si
voglia) che prende una chiamata HTTP. Questa chiamata verra' mandata ad un
webserver che la deve processare. Il webserver dovra' capire che la deve
passare attraverso qualche trasporto alla webapp che la processera' (e.g.,
wsgi) -- questo tipicamente coinvolge anche copiare dei buffer dal
webserver al worker della webapp --, il tuo coso dietro poi prende la
richiesta, la smonta (che so, parsa del json), pesca i dati che servono e
li passa al driver del db che a sua volta scrive sul db. Verosimilmente
questa operazione e' bloccante. Il che vuole dire che se hai troppa
concorrenza finisci i worker e cominci a tirare dei 503. E perdi dati. Male.

La tua idea di "riscrivere il magic method in Go" probabilmente rende un
po' piu' veloce il processamento dei dati (ma in compenso hai eventualmente
il problema di convertire gli stessi dal formato pythonoso che ricevi in
input e che quando il tuo handler viene chiamato sono gia' stati macinati e
li passi al metodo in Go, che poi parlera' con il db. Ora si pone il
problema di come fare in modo asincrono la richiesta al db (questo e' il
pezzo piu' interessante). Hai diversi approcci... e scegliere quello giusto
(per come funziona Go) e' il punto chiave del successo.

In tutto questo dal punto di vista delle ops, non ho idea di cosa cavolo
succeda. Per esempio non ho idea come un worker django si senta quando gli
crei sotto dei thread sotto le chiappe (questo fa il runtime di Go). Non ho
idea di *quando* li crei. Per esempio, se venissero creati appena carichi
la libreria condivisa, che verosimilmente potrebbe accadere *prima* che i
worker vengano forkati, ti troveresti potenzialmente con un runtime rotto
(i thread non sono copiati su una fork). Non so se il runtime di Go
gestisce questa cosa quando la fork la fa Python "da fuori". Nota che
proprio il problema delle interazioni fra fork e posix non e' banale ed e'
uno dei motivi per cui in Go non hai una vera e propria fork (ma solo un
"subprocess") e in Python rischi di brutto quando fai fork + thread (con
risultati disastrosi garantiti se hai la pretesa di fare anche logging).

Quello che voglio dirti e' che vai a mettere su un sistema
significativamente complesso, in cui devi capire molto di piu' di diverse
parti in movimento, con alcuni pezzi specialmente immaturi (non credo che
ci siano molti sistemi in produzione che servono Go tramite una libreria
condivisa da Python). Secondo me e' una situazione in cui prima o poi
qualcosa si spacca e non e' chiaro perche'.

Se il tuo problema e' "devo gestire tante scritture concorrenti"... beh,
vai su una situazione Go pura.

Intanto... dimenticati un ORM (mi sembra di avere capito che hai problemi
di performance, e un use case relativamente semplice: input in tabelle ben
definite). Se proprio lo vuoi, ce lo hai anche in Go. Ma potrebbe finire
per essere un collo di bottiglia (in Python come in Go).

La webapp la puoi scrivere in Go puro. Ci sono parecchie librerie di alto
livello per fare sta roba: ti trovi con un binarietto che devi tenere
eseguito che ascolta sulla porta che vuoi e ti prende tutte le post del
mondo. Non devi copiare dati avanti e indietro dal webserver al worker (o
usare qualunque tecnica "smart" che i webserver usano oggi). Gestisci la
concorrenza come vuoi: tipicamente una goroutine per richiesta e tanti
saluti: il tuo modello e' sufficientemente semplice che anche una tecnica
del genere dovrebbe funzionare.

E' roba *semplice*. E' piu' semplice che imparare abbastanza Go da fare il
super-metodo e poi imparare come fare parlare Python e Go.






-- 
.
..: -enrico-
-------------- parte successiva --------------
Un allegato HTML è stato rimosso...
URL: <http://lists.python.it/pipermail/python/attachments/20150826/3007c869/attachment-0001.html>


Maggiori informazioni sulla lista Python