Archivio | settembre, 2011

Multi-threading vs. node.js

26 Set

Ieri si è tenuta a Brescia la prima conferenza italiana dedicata a Node.js

Node.js è un framework event-driven I/O per il motore JavaScript V8. Si tratta di un framework relativo all’utilizzo server-side di Javascript per realizzare applicativi scalabili e real-time. È simile come funzionalità a Twisted in Python, Perl Object Environment in Perl o a Event machine in Ruby.Node.js è in questo momento una delle tecnologie più discusse in rete. Sicuramente Node.js avrà un ruolo fondamentale nei prossimi anni nello sviluppo di applicativi web data la continua e pressante richiesta di applicativi real-time e scalabili. Inoltre il linguaggio utilizzato è JavaScript, linguaggio ampiamente utilizzato e conosciuto dagli sviluppatori web.

Node.js, rispetto agli altri web server disponibili oggi sul mercato, ha un grande vantaggio: offre prestazioni molto elevate ed un consumo di risorse molto limitato. Node.js ha un’altra caratteristica peculiare: è un processo mono-thread.

L’obiettivo di Node.js è quello di fornire un modo semplice per costruire software di rete scalabili. Basta guardare il classico esempio “Hello world” per capire la radicale differenza rispetto agli altri web-server:

1
2
3
4
5
6
7
var http = require(‘http’);
http.createServer(function (req, res) {
  res.writeHead(200, {‘Content-Type’: ‘text/plain’});
  res.end(‘Hello World\n’);
}).listen(1337, “127.0.0.1”);
console.log(‘Server running at http://127.0.0.1:1337/’);
Node.js dice al sistema operativo (tramite epoll, kqueue, /dev/poll, o select) che dovrebbe essere notificato quando una nuova connessione viene fatta, e poi va a dormire. Ad ogni nuova connessione, poi esegue una callback. Ogni connessione necessità quindi di una piccola allocazione sullo heap. Questo è in contrasto con modello di concorrenza più comune di oggi, dove sono impiegati i thread del sistema operativo. Il Thread-based networking è relativamente inefficiente e molto difficile da usare (vedi: questo e questo ).

Node.js mostra tutta la sua efficienza nella gestione della memoria con carichi di lavoro elevati rispetto ai sistemi che per ogni connessione allocano 2MB di thread stack. Inoltre, gli sviluppatori di Node.js sono liberi da preoccupazioni di dead-lock del processo perchè non ci sono lock. Quasi nessuna funzione di Node.js esegue direttamente operazioni di I / O, così che il processo non si blocca mai. Visto che nessuno blocca nulla, anche programmatori meno esperti sono in grado di sviluppare sistemi molto performanti con il minimo sforzo. Altra nota interessante: utilizzando un solo thread per tutte le richieste gli sviluppatori non devono preoccuparsi del’accesso concorrente alle risorse perchè questo caso semplicemente non può avvenire: c’è un solo thread quindi solo una connessione accede ad un risorsa in un determinato istante.

Annunci

Codice Thread-safe

25 Set

Se il primo concetto era legato alla sintassi con cui scriviamo il nostro codice multi-thread (o concorrente) il secondo aspetto fondamentale è legato a come possiamo accedere agli oggetti che manipoliamo all’interno delle nostre applicazioni. Finchè usiamo un solo thread la creazione di un oggetto e la sua successivamente manipolazione non generano nessun problema. Quando invece abbiamo necessità di creare un oggetto in un thread e poi manipolarlo da altri dobbiamo fare in modo che all’oggetto sia applicato un lock affinche in un determinato istante ci sia soltanto un singolo thread che ci accede e per fare questo dobbiamo creare un lock prima di accedere all’oggetto e rilasciare il lock non appena terminato il lavoro con esso. Questo lock impedisce che più thread accedano in maniera parallela allo stesso oggetto. Da questo fatto si evince che se due o più thread tentano di accedere ad una istanza di un oggetto lo posso fare solo uno alla volta.

Delegate O Puntatori a Funzioni

22 Set

Perchè un blocco di codice sia eseguito in parallelo rispetto ad altre istruzioni e necessario identificarlo creado un metodo e darlo in pasto ad un qualcosa che sia capace di eseguire questo blocco di codice in modo asincrono. Perchè questo qualcosa sia capace di eseguire un qualsiasi metodo abbiamo bisogno di un livello di astrazione tra il nostro metodo ed il sistema che lo esegue in asincrono. Per creare questa astrazione ci serve un delegate ovvero un puntatore a funzione. L’unico vincolo che esiste tra il metodo e il delegate che punta a quel metodo e che entrambe abbiamo la stessa firma (quindi stesso numero e tipo di parametri e stesso tipo per quanto riguarda il valore di ritorno). Alcuni linguaggi per favorire questa operazione permettono la scrittura di metodi/funzioni anomini quindi metodi senza nome a cui ci si può riferire soltanto attraverso un delegate.

Programmazione Concorrente

19 Set

Alcuni anni fa, correva l’anno 2007, durante il TechEd avevo assistito a questa illuminante sessione dal titolo ”Irresistible Forces Meet the Movable Objects”. Il messaggio di Pat Helland sullo sviluppo software nel medio e lungo termine era molto chiaro: la frequenza dei clock ha raggiunto il limite e l’evoluzione va verso le CPU multi-core quindi la programmazione concorrente ed i relativi pattern devono diventare una delle conoscenze indispensabili per ogni programmatore professionista.

Oggi sono passati alcuni anni da quella lungimirante sessione e di questo topic se ne parla sempre di più. Basti pensare a quale sia l’hype per node.js ovvero un web-server che si programma in javascript dove tutto il codice non è bloccante: il risultato è una estrema scalabilità rispetto ad altri web-server “tradizionali”

Per quanto riguarda i diversi framework per lo sviluppo applicativo , sia web sia desktop, tutti di questi tempi hanno investito molti sforzi per agevolare la programmazione concorrente. Per esempio in un Ruby è stato introdotto Event machine mentre per il .NET framework, che fin dalla versione 1 supporta questo tipo di programmazione, sono stati introdotti la Task Parallel Library e Reactive Extensions

Insomma ogni piattaforma ha introdotto e/o sta introducendo funzionalità che hanno l’obiettivo di rendere semplice la creazione di applicazioni che sfruttano al 100% tutti i core presenti sui personal computer odierni e futuri. Già l’obiettivo è rendere semplice un compito che negli anni passati non era certo un argomento entry-level. La ragione fondamentale a mio avviso era la mancanza di conoscenze chiare in materia ma fortunatamente oggi la conoscenza in materia si è evoluta e perlomeno sono chiare una serie di problematiche comuni a tutti i linguaggi quando si parla di programmazione concorrente.

Patterns of parallel programming

Per chi vuole capire completamente cosa significa la programmazione concorrente (o multi-thread) il primo punto è capire quali sono gli schemi/scenari (ovvero i pattern) che si incontrano in questo mondo.

Al di la del tettaglio tecnologico questo documento di ben oltre 100 pagine dedicate all’attuale versione del .NET Framework è una buona lettura per chi vuole capire quali sono i pattern e gli anti-pattern da utilizzare o meno per creare software multi-thread di qualità.

Fonte: Patterns of parallel programming – Understanding and applying parallel patterns with the .net framework 4 and Visual C#

Parallel programming “for real”

Visto che nei prossimi mesi passerò la maggior parte delle mie giornate lavorative sviluppando un sistema che eroga informazioni in “real-time”, quindi fa largo uso della programmazione multi-thread, vorrei cercare di riassumere con alcuni post quelli che sono i problemi reali che si incontrano facendo un utilizzo quotidiano della programmazione concorrente.