PHP serialize, unserialize ineffizient

Beim Vergleich verschiedener Serialize-Algorithmen schneidet der PHP-Serializer am schlechtesten ab

Da es immer wieder Unklarheiten gibt darüber, wie schnell ein Serializer eine Datei zu einer komplizierten Datenstruktur wiederbelebt, habe ich mir mal die Mühe gemacht, dies genauer zu untersuchen. Hier die Datenstruktur:

# EAV: Entity Attribute Value
my $data = { env => { foo => 'bar' } };

Im Folgenden die verglichenen Algorithmen. Der Unterschied zwischen einer mit textlichen Mitteln (JSON, PHP-Serialize) serialisierten Sequenz und einer Low-Level-Serialisierung auf Byte-Ebene (Storable, eigene Algorithmen) wird deutlich:

PHP serialize/unserialize

Unter dem Schlüsselwort phpser in untenstehender Tabelle zu finden. Der Algorithmus, in PHP für die Funktionen serialize(), unserialize() zum Einsatz kommend, ist für diesen Test in Perl implementiert.

Von allen anderen Serialize-Algorithmen schneidet dieser am schlechtesten ab.

JSON

Als Funktionsname jsons in der Tabelle. Etwas schneller als der in PHP verwendetet Algorithmus.

Perl Storable::freeze/Storable::thaw

storab ist das Schlüsselwort für die Ergebnistabelle untenstehend.

Zwei eigene Entwicklungen

altern und atonce bilden ähnliche Algorithmen ab.

Ergebnis Benchmark

Am schlechtesten schneidet der PHP Serializer ab.

         Rate phpser  jsons storab altern atonce
phpser 1749/s     --   -55%   -74%   -79%   -82%
jsons  3879/s   122%     --   -42%   -53%   -60%
storab 6734/s   285%    74%     --   -18%   -31%
altern 8210/s   370%   112%    22%     --   -15%
atonce 9699/s   455%   150%    44%    18%     --

Benchmark Code

#!/usr/bin/perl

use strict;
use warnings;
use IO::String;
use Storable qw(freeze thaw);
use Data::Dumper;
use Benchmark qw(cmpthese timethese);
use PHP::Serialization qw(serialize unserialize);
use JSON;

# EAV: Entity Attribute Value
my $data = { env => { foo => 'bar' } };

# EAV im Wechsel serialisieen
my $altern = sub{
    my $io = IO::String->new;
    foreach my $ent( keys %$data){
        foreach my $att( keys %{$data->{$ent}} ){
            my $val = $data->{$ent}{$att};
            $io->print( pack('N', length $ent), $ent, pack('N', length $att), $att, pack('N', length $val), $val  );
        }
    }

    my $res = {};
    $io->seek(0,0);
    while( read($io, my $elen, 4)  ){
        read($io, my $ent, unpack('N', $elen));
        read($io, my $alen, 4);
        read($io, my $att, unpack('N', $alen));
        read($io, my $vlen, 4);
        read($io, my $val, unpack('N', $vlen));
        $res->{$ent}{$att} = $val;
    }
    #print Dumper $res;
};

# EAV am Stück serialisieren
my $atonce = sub{
    my $io = IO::String->new;
    foreach my $ent( keys %$data){
        foreach my $att( keys %{$data->{$ent}} ){
            my $val = $data->{$ent}{$att};
            $io->print( pack('NNN', length $ent, length $att, length $val), $ent, $att, $val  );
        }
    }
     my $res = {};
     $io->seek(0,0);
     while( read($io, my $buffer, 12) ){
        my ($elen,$alen,$vlen) = unpack 'NNN', $buffer;
        read($io, my $ent, $elen);
        read($io, my $att, $alen);
        read($io, my $val, $vlen);
        $res->{$ent}{$att} = $val;
     }
     #print Dumper $res;
};

my $storab = sub{
    my $io = IO::String->new;
    $io->print(freeze($data));
    $io->seek(0,0);
    my $str = '';
    while( read($io, my $buffer, 102) ){ $str .= $buffer }
    my $res = thaw($str);
    #print Dumper $res;
};


my $phpser = sub{
    my $io = IO::String->new;
    $io->print(serialize($data));
    $io->seek(0,0);
    my $str = '';
    while( read($io, my $buffer, 102) ){ $str .= $buffer }
    my $res = unserialize($str);
    #print Dumper $res;
};

my $jsons = sub{
    my $io = IO::String->new;
    $io->print(encode_json($data));
    $io->seek(0,0);
    my $str = '';
    while( read($io, my $buffer, 102) ){ $str .= $buffer }
    my $res = decode_json($str);
    #print Dumper $res;
};


cmpthese(10000, {
    'altern' => $altern,
    'atonce' => $atonce,
    'storab' => $storab,
    'phpser' => $phpser
});


Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. s​os­@rolf­rost.de.