Python migliora il supporto al multiprocessing

Con le seguenti parole Guido Van Rossum ha approvato e benedetto l’ingresso di pyprocessing all’interno della libreria standard di Python già nelle prossime release:

+1 from me as well, and I support the rename to multiprocessing (“processing” is just too much of a common word).
This will provide a good short-term answer to those who still clamor for dropping the GIL.

Tutti i Pythonisti attenti e aggiornati staranno già esultando ma è mio dovere spiegare a tutti gli altri il significato di questa notizia in termini pratici. Storicamente Python ha sempre avuto due modelli di concurrency basati sul sistema operativo: il modello a thread multipli (tramite il modulo threading) e quello a processi multipli (nel modulo os prima e con l’aggiunta di subprocess poi). Vi è almeno un terzo modello un po’ meno esplicito (che a me piace molto) che richiede cooperazione: l’uso dei generatori, che però non approfondirò in questa sede.

Con l’esplosione delle CPU multicore e i noti problemi del modello di thread a stato condiviso, negli ultimi anni si è sentito il bisogno di rispolverare l’uso dei vecchi e sani processi: scalano automaticamente su più core, non condividono stato e permettono gratuitamente di spostarsi da una architettura multicore ad una a più nodi senza grossi sforzi.

Purtroppo però l’API Python per la gestione dei processi è sempre stata un po’ ostica da utilizzare per vari motivi: la fork() non è portabile (Windows non la supporta), far comunicare vari processi significa conoscere i dettagli dell’uso di pipe, named pipe o socket e magari scontrarsi con i dettagli dei sistemi operativi non-Unix like (tanto per non nominare sempre lo stesso). Nella release 2.4 di Python è stato aggiunto il modulo subprocess che cerca di razionalizzare un po’ le varie syscall (fork, spawn, system, popen, CreateProcess, ecc.) dei vari sistemi operativi in maniera organica.

Un passo avanti sicuramente, ma ancora non si era raggiunta la semplicità d’uso del modulo threading. Questo empasse ha permesso la nascita, grazie a Richard M. Oudkerk, del modulo pyprocessing. Semplice, efficiente (Windows ha un supporto per i processi poco efficiente, tanto per cambiare), con una API che modella 1-1 quella di threading, multipiattaforma e con supporto a message passing (tramite code, pipe o socket), sincronizzazione, memoria condivisa, pooling e molto altro.

Proprio quello che la comunità aspettava. Questo modulo ha avuto un ottimo successo anche nel mondo reale (io e i miei colleghi lo usiamo ogni giorno per codice di produzione) e recentemente ne è stata proposta l’inclusione nella libreria standard tramite la PEP 371.

Guido ha detto la sua, ora non ci resta che aspettare!

Comments

  1. Davvero interessante, è una feature che mancava nel linguaggio…

  2. Alessandro says:

    Sarebbe interessante un approfondimento sui modelli di concurrency, compreso quello dei generatori.
    Eh si.. 🙂

  3. Francesco says:

    (io e i miei colleghi lo usiamo ogni giorno per codice di produzione)

    E quindi mi sembra legittimo chiedere un articolo con esempi di utilizzo di pyprocessing.

    Visto che hai citato i generatori, sarebbe utile anche una miniserie sul loro uso (un po’ come l’eccellente serie di Michele Simionato sulla gestione dei record)

    Grazie 🙂

  4. Bello processing, nemmeno gli esempi dei doc vanno:

    
    >>> from processing import Pool
    >>> def f(x):
    ...     return x*x
    ... 
    >>> pool = Pool(processes=4)
    >>> print pool.map(f, range(10))
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "threading.py", line 460, in __bootstrap
        self.run()
      File "threading.py", line 440, in run
        self.__target(*self.__args, **self.__kwargs)
      File "/usr/lib/python2.5/site-packages/processing/pool.py", line 207, in _handleTasks
        put(task)
    TypeError: expected string or Unicode object, NoneType found
    
  5. Lawrence says:

    Dubito che tutto sia stabile. È una 0.x dopotutto. E dubito anche che entri in toto nella stdlib. A mio avviso entreranno Process, Queue, Pipe, le primitive di sincronizzazione, Manager e Proxy. A me comunque gli esempi funzionano: http://pyprocessing.berlios.de/examples/ex_pool.py. È probabile che la doc online non sia aggiornata (anche perché si riferisce a 2 release fa)

  6. Bah, Pool non è che sia molto complicato, se non va neanche con l’esempio più semplice, e addirittura hangs l’interprete lasciando appesi processi child orfani, la vedo grigia…

    Molto rumore per nulla…

  7. Lawrence says:

    Parti dal presupposto errato che la lib entri così com’è, non vengano scritti test e venga immersa nel codice senza nemmeno venire spulciata 🙂 Non è una questione di complesso o meno. Si è deciso di farla entrare. I paletti sono appunto di questo genere.. fissare i bug, scrivere i test e sfoltirla

  8. Bah vabbè, a me una lib rilasciata con documentazione che riporta esempi che non vanno non fa una buona impressione. Comunque de gustibus 🙂

  9. Per questo dovreste tutti usare ampoule e non processing :P.

  10. @valentino: scusa, fino a ieri ho usato la casseruola media per fare il budino al cioccolato. Da oggi però ho deciso di migliorare la mia stabilità. Mi indicheresti qual è la componente di Twisted che devo usare?

  11. valentino says:

    Twisted Core e` sufficiente per utilizzare Ampoule, deve essere almeno la versione 8.0, consigliata la 8.1 perche` sistema molte cose.

  12. Ciao Lawrence
    E della soluzione Stackless Python che ne pensi?
    Anche se cmq penso che non scali su piu’ processori, o mi sbaglio?

  13. Lawrence Oluyede says:

    @uberto: non penso. Nel senso che non l’ho mai usato e l’unica volta che ho provato non compilava su OSX. Pero` so che quelli di Eve online lo usano con successo: http://www.tentonhammer.com/node/10044

Policy per i commenti: Apprezzo moltissimo i vostri commenti, critiche incluse. Per evitare spam e troll, e far rimanere il discorso civile, i commenti sono moderati e prontamente approvati poco dopo il loro invio.