:::: MENU ::::

Prestazioni di PHP, JavaScript, Ruby, Java e C++ a confronto

I linguaggi di programmazione per il web sono molti, pertanto capita spesso di chiedersi quale strumento sia meglio usare prima di sporcarsi le mani in un nuovo progetto. Non esiste una risposta semplice a questa domanda perché le prestazioni dipendono da molti fattori. Per darmi una prima risposta, che non pretende di essere esaustiva, ho voluto effettuare una comparativa tra 5 dei più diffusi per il web: PHP, JavaScript, Ruby, Java e C++ (ok, ho imbrogliato questo non è così diffuso per il web ma è un ottimo riferimento per questo benchmark).

Quanti di voi conoscono la torre di Hanoi?

La Torre di Hanoi è un rompicapo costituito da tre paletti e un numero di dischi di grandezza via via decrescente impilati su uno di questi paletti. Obiettivo del rompicapo è spostare tutti i dischi da una pila ad un altra potendo spostare soltanto un disco alla volta e potendo solo spostare un disco più piccolo al di sopra di uno più grande, mai viceversa.

Dietro al gioco esiste una dimostrazione matematica che esplicita il numero minimo di mosse necessarie alla risoluzione del gioco e, assieme a questa anche un algoritmo per la risoluzione del gioco: se n è il numero di dischi, il numero minimo di mosse per completare il rompicapo è 2^n-1.

Il test

Ho pubblicato su GitHub un repository contenente l’algoritmo di risoluzione nei 5 linguaggi (PHP, JavaScript, Ruby, Java e C++) e uno script bash che effettua la compilazione dei sorgenti e l’esecuzione del codice nei diversi linguaggi.

Il codice è stato realizzato sfruttando il più possibile le strutture dati preesistenti dei vari linguaggi: ad esempio per C++ è stata usata la struttura stack presente nella Standard Template Library, array associativi nel caso di PHP e il classico oggetto Array di JavaScript.

Per la natura del problema il codice di risoluzione è stato implementato in tutti i linguaggi come un algoritmo ricorsivo. Riporto a titolo esemplificativo il codice nella versione Javascript, gli altri sono analoghi e sono consultabili sul repository GitHub.


var s1 = [];
var s2 = [];
var s3 = [];
var movesCount = 0;

Array.prototype.top = function() {
    return this[this.length - 1];
};

Array.prototype.isEmpty = function() {
    return this.length === 0;
};

function printStack(currStack) {
    var temp = [];
    var str = "";
    var oss = "";

    while (!currStack.isEmpty()) {
        temp.push(currStack.pop());
    }

    while (!temp.isEmpty()) {
        currStack.push(temp.top());
        oss += temp.top() + " ";
        temp.pop();
    }

    return oss;
}

function hanoi(source, dest, swap, depth) {
    if (depth == 1) {
        dest.push(source.top());
        source.pop();
        movesCount++;

        return;
    }
    // spostare la torre depth-1 strati preesistente in swap
    hanoi(source, swap, dest, depth - 1);

    // fare la seguente mossa
    dest.push(source.top());
    source.pop();
    movesCount++;

    // ricreare la torre di depth-1 strati sopra la destinazione
    hanoi(swap, dest, source, depth - 1);
}

function emptyStack(stack) {
    while (!stack.isEmpty()) {
        stack.pop();
    }
}

function playGame(decks, quiet) {
    s1 = [];
    s2 = [];
    s3 = [];
    emptyStack(s1);
    emptyStack(s2);
    emptyStack(s3);
    movesCount = 0;
    for (i = 0; i < decks; ++i) {
        s1.push(i);
    }
    if (!quiet) {
        console.log("Inizio");
        console.log("Stack1: " + printStack(s1));
        console.log("Stack2: " + printStack(s2));
        console.log("Stack3: " + printStack(s3));
    }

    var startTime = +new Date();

    hanoi(s1, s3, s2, decks);

    var finishTime = +new Date();

    if (!quiet) {
        console.log("Fine");
        console.log("Stack1: " + printStack(s1));
        console.log("Stack2: " + printStack(s2));
        console.log("Stack3: " + printStack(s3));
    }

    var totalTime = (finishTime - startTime) / 1000;
    console.log("decks:\t" + decks + "\ttime:\t" + totalTime + "\n");

}

// MAIN
console.log("Entry point");
var decks = parseInt(process.argv[2]);

playGame(decks, true);

I risultati del test

Il test è stato eseguito su un iMac mid 2010 (OSX 10.11.1) con le seguenti versioni di compilatori o interpreti:

  • php 5.5.29
  • node v0.12.0
  • ruby 2.0.0p645
  • javac 1.7.0_71
  • g++ LLVM 7.0.0

Prima di trarre qualsiasi conclusione è bene ricordare che il test prende in considerazione soltanto alcune funzionalità dei linguaggi :

  • allocazione di variabili e oggetti
  • allocazione della memoria stack
  • Passaggio di parametri per riferimento

che sono tutte operazioni sostanzialmente in carico alla CPU e memoria, quindi non stiamo considerando come i linguaggi si comportano su altri tipi di operazioni come ad esempio I/O di grandi quantitativi di dati su memoria o disco. Inoltre i tempi di esecuzione sono calcolati come il tempo che intercorre tra la prima e l’ultima mossa del rompicapo. Sono quindi esclusi tutti i tempi di overhead di caricamento dello script e interpretazione del codice.

Qui di seguito riporto i tempi di esecuzione dell’algoritmo espressi in secondi, al variare del numero di dischi tra 18 e 24.

Num. Dischi C++ Javascript Java Ruby PHP
18 0.0020 0.0040 0.0480 0.0632 0.2907
19 0.0050 0.0070 0.0570 0.1253 0.5959
20 0.0063 0.0083 0.0740 0.2385 1.1870
21 0.0190 0.0290 0.1130 0.5033 2.5338
22 0.0330 0.0430 0.1690 0.9547 4.8684
23 0.0760 0.0860 0.3060 2.0705 10.1063
24 0.1260 0.1690 0.5710 3.8711 20.3050

Dai dati e dal grafico si legge chiaramente la complessità asintotica O(2^n) dell’algoritmo. Ciò che emerge di interessante sono le ottime prestazioni dei linguaggi C++ (ma questo era facilmente intuibile), Java e Javascript.

benchmark-php-ruby-javascript-java-c-hanoi

Eliminando dal grafico le serie relative a Ruby e PHP, osserviamo che Javascript si attesta a livelli di prestazioni molto simili a quelli di C++, cosa non scontata, data la diversa natura di linguaggio interpretato del primo e compilato del secondo, a prova dell’ottimo lavoro fatto nello sviluppo e ottimizzazione del motore V8 che sta alla base di Node.js

benchmark-javascript-java-c-hanoi

Linguaggi molto diffusi come Ruby e soprattutto PHP soffrono parecchio il confronto: già con 22 dischi Ruby impiega quasi 1 secondo per portare a termine l’algoritmo, PHP quasi 5 secondi, mentre Javascript si attesta a circa 170 millisecondi.


Personalizzare Google Map del tema Divi per WP

google-map-styled

Ci sono molti temi interessanti per WordPress, uno di questi è il tema Divi di ElegantThemes. Il tema è decisamente flessibile e di facile utilizzo ed incorpora diversi elementi grafici attraverso i quali è possibile creare layout grafici complessi.

Tra i vari elementi che si possono aggiungere ad una pagina c’è la Google Map, la quale però non è molto personalizzabile di default. Mi è capitato infatti di avere l’esigenza di inserire una Google Map in modalità grayscale (si può trovare una utile discussione su come desaturare le mappe google utilizzando le APIv3 a questo indirizzo) e di dover cambiare l’iconcina del marker. Vediamo come realizzare questa modifica.

Creazione del child theme

Dobbiamo innanzitutto creare un child theme per il tema Divi, in modo da evitare di “sporcare” il codice originale con le nostre modifiche (consiglio il plugin Child Theme Configurator per creare il proprio child theme).

Una volta creato il child theme copiamo dalla directory del tema Divi a quella del tema child i seguenti file

[directory tema child]/images/marker.png
[directory tema child]/js/custom.js

Creiamo, se non è già stato creato dal plugin anche il file

[directory tema child]/functions.php

Modifiche al codice del child theme

Le modifche da fare sono alla riga 1436 del file js/custom.js. E’ necessario commentare la riga che setta l’attributo mapTypeId ed aggiungere le righe che aggiungono gli attributi mapTypeControlOptionsmapTypeIds.

$this_map_container.data('map', new google.maps.Map( $this_map[0], {
	zoom: parseInt( $this_map.data('zoom') ),
	center: new google.maps.LatLng( parseFloat( $this_map.data('center-lat') ) , parseFloat( $this_map.data('center-lng') )),
	// mapTypeId: google.maps.MapTypeId.ROADMAP,
	scrollwheel: $this_map.data('mouse-wheel') == 'on' ? true : false,
	mapTypeControlOptions: {
         mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'tehgrayz']
    }
}));

Appena al di sotto poi bisogna aggiungere le seguenti righe per creare un nuovo stile per la mappa che sostanzialmente applica una desaturazione a tutti gli elementi (strade, fiumi, etichette, ecc) che compongono la mappa. Lo stile viene poi associato ed utilizzato dalla mappa attraverso la chiamata alla funzione setMapTypeId.

var mapType = new google.maps.StyledMapType([
    {
      featureType: "all",
      elementType: "all",
      stylers: [
        { saturation: -100 } // applicazione della desaturazione a tutti gli elementi
      ]
    }
], { name:"Grayscale" });    
$this_map_container.data('map').mapTypes.set('tehgrayz', mapType);
$this_map_container.data('map').setMapTypeId('tehgrayz');

Per modificare il marker da utilizzare è necessario modificare la riga 1468 come segue

icon: { url: et_custom2.images_uri + '/marker.png', size: new google.maps.Size( 46, 43 ), anchor: new google.maps.Point( 16, 43 ) },

In pratica andiamo a richiamare l’oggetto et_custom2 al posto dell’oggetto et_custom, che andremo a definire modificando il file functions.php.

Successivamente dobbiamo editare il file functions.php. Aggiungiamo il seguente codice al file:

function child_et_divi_load_scripts_styles(){
	global $wp_styles;

	$template_dir = get_stylesheet_directory_uri();

	$theme_version = et_get_theme_version();
	
	wp_enqueue_script( 'divi-custom-script', $template_dir . '/js/custom.js', array( 'jquery' ), $theme_version, true );
	wp_localize_script( 'divi-custom-script', 'et_custom2', array(
		'images_uri'                    => $template_dir . '/images',
	) );
}

add_action( 'wp_enqueue_scripts', 'child_et_divi_load_scripts_styles' );

Questo hook viene eseguito nel momento in cui WordPress inserisce nelle pagine le risorse javascript. Con questa modifica WP carica la versione del file custom.js contenuta nel child theme anzichè quella del parent theme. La chiamata alla funzione wp_localize_script permette di definire un oggetto et_custom2 che permetterà di impostare la nuova directory dell’immagine marker da utilizzare.

A questo punto, una volta salvati i file modificati, tutte le mappe del sito verranno visualizzate con il nuovo stile in scala di grigi. E verrà utilizzato il marker presente nella cartella images del tema child.


Risolvere i problemi dell’indirizzo noreply in BBPress

Come ben sapete tra i tanti plugin WordPress c’è l’ottimo bbPress per la creazione e gestione di forum integrati al nostro sito/blob.

Mi sono da poco imbattuto in un problema piuttosto particolare nella generazione dell’indirizzo email noreply per il sito della mia Web Agency Spicelab. Accade che quando impostiamo nelle impostazioni di WordPress l’URL del nostro sito omettendo la componente www, avviene uno strano troncamento del nome a dominio nell’indirizzo noreply presente nelle email di notifica generate da bbPress.Errore generazione noreply bbpress

Ad esempio, se impostiamo nelle Impostazioni generali di Wp come URL sito

http://miosito.it

vedremo nel campo mittente delle email di notifica, che bbPress avrà generato l’indirizzo noreply@osito.it, troncando così le prime lettere del nome a dominio.

Il problema NON si verifica se nelle Impostazioni generali di Wp impostiamo come URL sito

http://www.miosito.it

Come sistemare la generazione dell’indirizzo noreply

Per risolvere la cosa è necessario mettere mano direttamente ai file del plugin, fintanto che il codice non verrà fixato dagli autori del plugin.

Apriamo il file wp-content/plugins/bbpress/includes/common/functions.php ed modifichiamo come segue le rige 1065 e 1205:

// commentiamo il codice preesistente
// $do_not_reply  = '<noreply@' . ltrim( get_home_url(), '^(http|https)://' ) . '>';
$do_not_reply = '<noreply@' . ltrim( get_home_url(), '^(http|https)://' ) . '>';
$do_not_reply = '<noreply@' . preg_replace('^(https?:\/\/)(www\.)?', "", get_home_url()) . '>';

A questo punto è sufficiente provare a sottoscriversi alle notifiche email per un qualsiasi thread del nostro forum per verificare se l’indirizzo noreply viene generato correttamente.


Il 2015 inizia con Spicelab

Quest’anno mi imbarcherò in una nuova, importante e stuzzicantissima avventura, assieme ad altri tre professionisti del Web, con i quali unirò le mie competenze nella realizzazione di siti web, app per smartphone e tablet, web marketing e social media: nasce il progetto Spicelab!

Il progetto Spicelab

Il nome nasce con in mente le spezie perché i componenti della nostra squadra, con le loro diverse e complementari competenze, sono ingredienti che uniti assieme danno ogni volta un risultato unico e particolare.

Nella squadra il mio ruolo è di occuparmi degli aspetti tecnici ed implementativi di siti web ed app.

I servizi offerti da Spicelab

Senza falsa modestia pensiamo che le persone e le aziende che si rivolgono a Spicelab si fidelizzeranno con noi grazie ai risultati ottenuti, non perché forzati da contratti onerosi o piattaforme software complicate nell’utilizzo autonomo.
I servizi che offriamo mirano alla creazione, cura e potenziamento di un’efficace presenza online per i nostri clienti e per farlo utilizziamo tecnologie allo stato dell’arte dell’industria del web, con un occhio di riguardo verso il mondo Open Source.

Realizzare un sito web è solo l’inizio: attualmente, difficilmente è sufficiente per incrementare il traffico proveniente da contatti veramente appartenenti al target di interesse del cliente. Ecco che allora all’offerta Spicelab si aggiungono:

  • realizzazione di siti web ed ecommerce
  • creazione di app per smartphone e tablet Android ed iOS
  • campagne web marketing
  • ottimizzazione per i motori di ricerca
  • redazione di contenuti e web copywriting
  • apertura e gestione di profili social media
  • social media marketing
  • design grafico e branding
  • corsi di formazione in aula e one-to-one

Logo spicelab

Se sono riuscito ad incuriosirti su cosa Spicelab può fare per te, vieni a trovarci sul nostro sito o scrivici direttamente a info@spicelab.it!


Gestire le librerie con Android Studio e Git submodule

Può capitare che sviluppando un’app Android si riveli utile creare delle librerie di codice riutilizzabili in diversi progetti.

Utilizzando Eclipse il procedimento è abbastanza semplice, dato che ogni libreria è un progetto a sè stante e può essere associata a uno o più progetti. E’ anche facile metterla sotto controllo di versione con Git o altri VCS.

Utilizzando invece Android Studio, gestire le librerie si rivela un po’ più complesso. In Android Studio infatti ogni libreria è memorizzata all’interno della directory principale dell’app che la utilizza. Se a questo punto si volesse mettere sotto versioning la directory dell’app, si andrebbe ad aggiungere anche la cartella della libreria, mentre l’obiettivo è quello di tenere il versioning della libreria separato da quello dell’app.

Continua a leggere


Pagine:12345