- PVSM.RU - https://www.pvsm.ru -
Как известно, переменная в PHP это не только ценные данные, а целый контейнер zval. А массив таких переменных занимает в памяти чересчур много места.
В PHP есть реализация Judy [1] массивов — быстрых, ассоциативных и потребляющих на порядок меньше памяти. Но, к сожалению, методов сериализациидесериализации для них не существует.
Меня интересовала сериализация только целочисленных массивов, т.е. как и индекс массива, так и его значение только целые числа. Её я и реализовал, добавив необходимые методы в исходный код расширения. Принцип сериализации прост:
Массив ( 200 => 0, 300 => -5000, -100 =>2000 ) превращается в строку
"+c8+0+12c-1388-64+7d0"
Есть два места, где можно взять исходники:
Было выбрано второе. Все изменения сделаны в php_judy.c
Жирным шрифтом показаны добавленные строки.
/* implements some interface to provide access to judy object as an array */
zend_class_implements(judy_ce TSRMLS_CC, 1, zend_ce_arrayaccess, zend_ce_iterator);
zend_class_implements(judy_ce TSRMLS_CC, 1, zend_ce_serializable);
judy_ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
PHP_METHOD(judy, memoryUsage);
PHP_METHOD(judy, serialize);
PHP_METHOD(judy, unserialize);
PHP_METHOD(judy, count);
ZEND_BEGIN_ARG_INFO_EX(arginfo_judy_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0,str)
ZEND_END_ARG_INFO()
PHP_ME(judy, memoryUsage, NULL, ZEND_ACC_PUBLIC)
PHP_ME(judy, serialize, NULL, ZEND_ACC_PUBLIC)
PHP_ME(judy, unserialize, arginfo_judy_unserialize, ZEND_ACC_PUBLIC)
PHP_ME(judy, count, arginfo_judy_count, ZEND_ACC_PUBLIC)
PHP_METHOD(judy, serialize)
{
JUDY_METHOD_GET_OBJECT
if ( intern->type == TYPE_INT_TO_INT ) {
long int index = 0, i = 0, l;
long int * PValue;
char * s;
Word_t idx1 = 0, idx2 = -1, Rc_word;
JLC(Rc_word, intern->array, idx1, idx2);
l = 64 + ( Rc_word << 3 );
s = emalloc ( l );
if ( s == NULL ) RETURN_NULL();
JLF ( PValue, intern->array, index );
while ( PValue != NULL && PValue != PJERR ) {
JLG ( PValue, intern->array, index );
if ( index < 0 ) {
if ( *PValue < 0 ) sprintf ( s+i, "-%x-%x", -index, -*PValue );
else sprintf ( s+i, "-%x+%x", -index, *PValue );
} else {
if ( *PValue < 0 ) sprintf ( s+i, "+%x-%x", index, -*PValue );
else sprintf ( s+i, "+%x+%x", index, *PValue );
}
i += strlen ( s+i );
if ( i > l - 50 ) {
l <<= 1;
s = erealloc ( s, l );
if ( s == NULL ) RETURN_NULL();
}
JLN ( PValue, intern->array, index );
}
*(s+i) = 0;
RETURN_STRING ( s, 0 );
}
RETURN_NULL();
}
long int Hex2Int ( char * s, long int * j, long int l ) {
long int v = 0;
char sym;
if ( s[*j] == '+' ) {
(*j)++;
sym = s[*j];
while ( sym != '+' && sym != '-' && *j < l ) {
v <<= 4;
if (( sym >= '0' ) && ( sym <= '9' )) v += ( sym - '0' );
else v += ( sym - 'a' + 10 );
(*j)++;
sym = s[*j];
}
} else {
(*j)++;
sym = s[*j];
while ( sym != '+' && sym != '-' && *j < l ) {
v <<= 4;
if (( sym >= '0' ) && ( sym <= '9' )) v -= ( sym - '0' );
else v -= ( sym - 'a' + 10 );
(*j)++;
sym = s[*j];
}
}
return v;
}
PHP_METHOD(judy, unserialize)
{
JUDY_METHOD_GET_OBJECT
intern->counter = 0;
intern->type = TYPE_INT_TO_INT;
intern->array = (Pvoid_t) NULL;
char * s;
long int l, j = 0;
Word_t * PValue, index, value;
if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s, &l) == FAILURE) return;
if ( l < 4 ) return;
while ( j < l ) {
index = Hex2Int ( s, &j, l );
value = Hex2Int ( s, &j, l );
JLI ( PValue, intern->array, index );
if ( PValue == NULL || PValue == PJERR ) return;
*PValue = value;
}
return;
}
phpize
./configure
make
make install
extension=judy.so
<?php
function InitArray ( &$ar, $init_srand, $max ) {
srand ( $init_srand );
for ( $i = -$max; $i < $max; $i++ ) {
$index = rand ( -$max, $max );
$value = rand ( -1000, 1000 );
$ar[$index] = $value;
}
}
function ShowTime ( $st, $text ) {
printf ( "$text in %.2f sec.n", microtime ( true ) - $st );
}
$init_srand = time ();
$max = 500000;
echo "srand = $init_srand, max = $maxn";
$init_mem = memory_get_usage();
$st = microtime ( true );
$a = array ();
InitArray ( $a, $init_srand, $max );
ShowTime ( $st, "Initialized std. array" );
echo "Elements in std. array: " , count ( $a ) , "n";
echo "Used memory: " , (memory_get_usage()-$init_mem) , " bytesnn";
$st = microtime ( true );
$j = new Judy(Judy::INT_TO_INT);
InitArray ( $j, $init_srand, $max );
ShowTime ( $st, "Initialized Judy array" );
echo "Elements in Judy array: " , count ( $j ) , "n";
echo "Used memory: " , $j->memoryUsage() , " bytesnn";
$st = microtime ( true );
$a_ser = serialize ( $a );
ShowTime ( $st, "Serialized std. array" );
$st = microtime ( true );
$j_ser = serialize ( $j );
ShowTime ( $st, "Serialized Judy array" );
echo "Serialized std. length: " , strlen ( $a_ser ) , "n";
echo "Serialized Judy length: " , strlen ( $j_ser ) , "nn";
$st = microtime ( true );
$a_unser = unserialize ( $a_ser );
ShowTime ( $st, "Unserialized std. array" );
$st = microtime ( true );
$j_unser = unserialize ( $j_ser );
ShowTime ( $st, "Unserialized Judy array" );
if (count ( $j_unser ) != count ( $a )) die ( "ERROR: arrays size mismatchn" );
foreach ( $a as $index => $value ) {
if ( $j_unser[$index] != $value ) {
die ( "ERROR: arrays data mismatchn" );
}
}
echo "OK: std. array and unserialized Judy array are identicaln";
?>
На выходе получаем
srand = 1348822174, max = 500000
Initialized std. array in 0.76 sec.
Elements in std. array: 632067
Used memory: 49703784 bytes
Initialized Judy array in 0.98 sec.
Elements in Judy array: 632067
Used memory: 3247108 bytes
Serialized std. array in 0.33 sec.
Serialized Judy array in 0.18 sec.
Serialized std. length: 9904186
Serialized Judy length: 6061744
Unserialized std. array in 0.13 sec.
Unserialized Judy array in 0.08 sec.
OK: std. array and unserialized Judy array are identical
<?php
$j = new Judy(Judy::INT_TO_INT);
$j[0] = 456;
$j[-1] = 123;
foreach ( $j as $index => $value ) {
echo "$index $valuen";
}
?>
Был создан запрос «foreach [0] [-1]» [4]. При желании он легко исправляется.
Автор: ubx7b8
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/50163
Ссылки в тексте:
[1] Judy: http://php.net/manual/en/intro.judy.php
[2] pecl.php.net/package/judy: http://pecl.php.net/package/judy
[3] github.com/orieg/php-judy: https://github.com/orieg/php-judy
[4] «foreach [0] [-1]»: https://github.com/orieg/php-judy/issues/3
[5] Источник: http://habrahabr.ru/post/200246/
Нажмите здесь для печати.