Подтвердить что ты не робот

Доступ к большим массивам в PHP

Я занимался профилированием различных методов доступа к массивам больших (ish) данных в PHP. Практический пример довольно прост: некоторые из наших инструментов выводят данные в файлы PHP как ассоциативные массивы, и эти файлы считаются статическими данными приложением. Мы делаем игры, поэтому некоторые примеры файлов данных будут включать элементы в каталоге, задачи, которые должен выполнить пользователь, или определения для карт:

<?php
$some_data = array(
    ...lots and lots of stuff in here...
);
?>

Поскольку эти массивы являются большими (400 КБ), и большая часть нашего кода заинтересована в этих данных, становится необходимо как можно более эффективно получать доступ к этим данным. Я решил использовать 3 разных шаблона для этого. Представляя методы, я поделюсь своими результатами ниже.

То, что я ищу, - это некоторые проверки на основе этих методов и их время, а также любые другие методы, которые можно попробовать.

Метод # 1: функция getter

В этом методе экспортер фактически создает файл, который выглядит так:

<?php
function getSomeData()
{
    $some_data = array(
        ...lots and lots of stuff here...
    );
    return $some_data;
}
?>

Клиентский код может затем получить данные, просто вызвав getSomeData(), когда они этого захотят.

Метод # 2: глобальный + включить

В этом методе файл данных выглядит идентично исходному коду блока выше, однако клиентский код должен перескакивать через несколько обручей, чтобы получить данные в локальной области. Это предполагает, что массив находится в файле с именем 'some_data.php';

global $some_data; //must be the same name as the variable in the data file...
include 'some_data.php';

Это приведет к массиву $some_data в область видимости, хотя это немного громоздко для кода клиента (мое мнение).

Метод № 3: получение по ссылке

Этот метод почти идентичен методу # 1, однако функция getter не возвращает значение, а скорее задает ссылку на данные.

<?php
function getSomeDataByRef($some_data)
{
    $some_data = array(
        ...lots and lots of stuff here...
    );
    return $some_data;
}
?>

Затем код клиента извлекает данные, объявляя локальную переменную (называемую чем угодно) и передавая ее по ссылке на getter:

$some_data_anyname = array();
getSomeDataByRef(&$some_data_anyname);

Результаты

Итак, я запустил немного script, который запускает каждый из этих методов получения данных 1000 раз и усредняет время выполнения (вычисленное microtime (true) в начале и в конце). Ниже приведены мои результаты (в мс, работающие на MacBookPro 2 ГГц, 8 ГБ оперативной памяти, версия PHP 5.3.4):

МЕТОД №1:

AVG: 0,0031637034416199 MAX: 0,0043289661407471 MIN: 0.0025908946990967

МЕТОД № 2:

AVG: 0.01434082698822 MAX: 0,018275022506714 MIN: 0.012722969055176

МЕТОД № 3:

AVG: 0,00335768699646 MAX: 0,0043489933013916 MIN: 0.0029017925262451

В любом случае, из этих данных ясно, что метод global + include уступает другим, что является "незначительной" разницей.

Мысли? Я что-то совсем не вижу? (Наверное...)

Спасибо заранее!

4b9b3361

Ответ 1

Не уверен, что это именно то, что вы ищете, но оно должно помочь в решении проблем со скоростью и памятью. Вы можете использовать фиксированный массив массивов:

$startMemory = memory_get_usage();
$array = new SplFixedArray(100000);
for ($i = 0; $i < 100000; ++$i) {
    $array[$i] = $i;
}
echo memory_get_usage() - $startMemory, ' bytes';

Подробнее о больших массивах php читайте здесь: http://nikic.github.com/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html

Также вы подумали о сохранении данных в кеше/памяти? Например, вы можете использовать mysqlite с движком inmemory при первом выполнении, а затем получить доступ к данным:

$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// .. Use PDO as normal

Ответ 2

Для одного из моих проектов, в которых база данных не была опцией, я столкнулся с такой же проблемой загрузки больших (большими я имею в виду серии из 3 МБ файлов) php файлов, содержащих массивы в памяти, и я искал варианты для максимизации спектакли. Я нашел очень простой, который кешировал эти файлы на диске как json при первом использовании. Я разделил время загрузки на 3, а пиковое потребление памяти на 30%. Загрузка локального json файла с помощью json_decode() намного быстрее, чем включение большого файла php, содержащего массив. это также имеет преимущество в том, что формат, который большинство языков может манипулировать напрямую. Надеюсь, что это поможет.