PHP Objects vs Arrays - Сравнение производительности при итерации

У меня есть огромное количество объектов PHP для нейронной сети, для которой я должен перебирать и выполнять некоторые математические операции. Мне было интересно, не лучше ли мне использовать ассоциативный массив над экземплярами классов?

Я имею дело с объектами 3640 и итерацией вокруг 500 раз (в лучшем случае) поверх этого, поэтому любая микро-оптимизация очень помогает. Было бы неизбежно быстрее $object['value'] сделать $object->value?

Изменить:. Они одинаковы. Но я думаю, что для конструктора будет немного накладных расходов? В любом случае, я не думаю, что хочу обменять мои красивые классы на грязные массивы: P

Ответ 1

Основанный на коде Quazzle, я выполнил следующий код (5.4.16 windows 64bits):

<?php
class SomeClass {
    public $aaa;
    public $bbb;
    public $ccc;
    }

function p($i) {
  echo '<pre>';
  print_r($i);
  echo '</pre>';
}


$t0 = microtime(true);
$arraysOf=array();
$inicio=memory_get_usage(); 
for ($i=0; $i<1000; $i++) {
    $z = array();
    for ($j=0; $j<1000; $j++) {
        $z['aaa'] = 'aaa';
        $z['bbb'] = 'bbb';
        $z['ccc'] = $z['aaa'].$z['bbb'];            
    }
    $arraysOf[]=$z;
}
$fin=memory_get_usage();    
echo '<p>arrays: '.(microtime(true) - $t0)."</p>";
echo '<p>memory: '.($fin-$inicio)."</p>";
p($z);

$t0 = microtime(true);
$arraysOf=array();
$inicio=memory_get_usage(); 
for ($i=0; $i<1000; $i++) {
    $z = new SomeClass();
    for ($j=0; $j<1000; $j++) {
        $z->aaa = 'aaa';
        $z->bbb = 'bbb';
        $z->ccc = $z->aaa.$z->bbb;          
    }
    $arraysOf[]=$z;
}
$fin=memory_get_usage();    
echo '<p>arrays: '.(microtime(true) - $t0)."</p>";
echo '<p>memory: '.($fin-$inicio)."</p>";
p($z);

$t0 = microtime(true);
$arraysOf=array();
$inicio=memory_get_usage(); 
for ($i=0; $i<1000; $i++) {
    $z = new stdClass();
    for ($j=0; $j<1000; $j++) {
        $z->aaa = 'aaa';
        $z->bbb = 'bbb';
        $z->ccc = $z->aaa.$z->bbb;          
    }
    $arraysOf[]=$z;
}
$fin=memory_get_usage();    
echo '<p>arrays: '.(microtime(true) - $t0)."</p>";
echo '<p>memory: '.($fin-$inicio)."</p>";
p($z);  
?>

И я получил следующий результат:

arrays: 1.8451430797577

memory: 460416

Array
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 1.8294548988342

memory: 275696

SomeClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 2.2577090263367

memory: 483648

stdClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

Заключение для php 5.4

  • Класс - это посты, чем массивы (но незначительно).
  • stdClass является злым.
  • Класс использует меньше памяти, чем массивы. (примерно на 30-40% меньше!!)

ps: как примечание, если класс определен, но члены тогда, использование этого класса медленнее. Он также использует больше памяти. Очевидно, секрет заключается в определении членов

Update

Я обновил с php 5.4 до php 5.5 (5.5.12 x86 windows).

arrays: 1.6465699672699

memory: 460400

Array
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 1.8687851428986

memory: 363704

SplFixedArray Object
(
    [0] => aaa
    [1] => bbb
    [2] => aaabbb
)

arrays: 1.8554251194

memory: 275568

SomeClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 2.0101680755615

memory: 483656

stdClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

Заключение для php 5.5

  • Для массивов PHP 5.5 быстрее PHP 5.4, для объекта он почти такой же
  • Класс медленнее, чем массивы, благодаря оптимизации PHP 5.5 и массивов.
  • stdClass является злым.
  • Класс по-прежнему использует меньше памяти, чем массивы. (на 30-40% меньше!!).
  • SplFixedArray похож на использование класса, но он использует больше памяти.

Ответ 2

Я использовал этот код для "профилирования" (1000 экземпляров, 1000 000 операций чтения/записи):

function p($i) {
  echo '<pre>';
  print_r($i);
  echo '</pre>';
}


$t0 = microtime(true);
for ($i=0; $i<1000; $i++) {
    $z = array();
    for ($j=0; $j<1000; $j++) {
        $z['aaa'] = 'aaa';
        $z['bbb'] = 'bbb';
        $z['ccc'] = $z['aaa'].$z['bbb'];
    }
}
echo '<p>arrays: '.(microtime(true) - $t0);
p($z);

$t0 = microtime(true);
for ($i=0; $i<1000; $i++) {
    $z = (object) null;
    for ($j=0; $j<1000; $j++) {
        $z->aaa = 'aaa';
        $z->bbb = 'bbb';
        $z->ccc = $z->aaa.$z->bbb;
    }
}
echo '<p>obj: '.(microtime(true) - $t0);
p($z);

echo '<p> phpversion '.phpversion();

Он выводит на моем хостинге LINUX этот материал:

arrays: 1.1085488796234

Array
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
obj: 1.2824709415436

stdClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
phpversion 5.2.17

поэтому в заключении: объекты медленнее даже на PHP 5.2. Не используйте объекты, если вам действительно не нужны их функции oop.

Ответ 3

Я использую код magallanes под php 7.0.9:

arrays: 0.19802498817444

memory: 324672

Array
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
arrays: 0.18602299690247

memory: 132376

SomeClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
arrays: 0.1950249671936

memory: 348296

stdClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

И пользователь php 7.1.3:

arrays: 0.59932994842529
memory: 444920
Array
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 0.72895789146423
memory: 164512

SomeClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)

arrays: 0.61777496337891
memory: 484416
stdClass Object
(
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)                      

Ответ 4

Вы не показали нам код для того, как работает $object->value, так как это может быть тот бэкэнд, это массив, в котором теоретически использование массива будет быстрее, так как оно включает в себя еще один вызов функции. Стоимость выполнения поиска, вероятно, будет огромной по сравнению с вызовом функции. Если это переменная, будет очень мало различий, поскольку объекты и массивы в PHP имеют очень похожую реализацию.

Если вы ищете оптимизацию, вам потребуется профиль, чтобы проверить, где используется большая часть времени. Я подозреваю, что изменение объектов на массивы не будет иметь большого значения.

Ответ 5

Я вижу, что это своего рода старое сообщение, поэтому я решил обновить его. вот мои коды и статистика, сделанные на Zend CE 5.3.21 Я попытался проверить все это, сохранив информацию и потянув ее обратно.

V1: занимает 0,83 с

for ($i=1; $i<1000000; $i++) {
  $a = get_one();
  $b = $a[0];
  $b = $a[1];
}

function get_one() {
  return array(1,1);
}

V2: занимает 3.05 сек

for ($i=1; $i<1000000; $i++) {
  $a = get_one();
  $b = $a->v;
  $b = $a->k;
}

function get_one() {
  $ret = new test();
  $ret->v = 1;
  $reb->k = 1;
  return $ret;
}

class test {
  public $v;
  public $k;
}

V3: занимает 1,98 секунды (обратите внимание, что конструктор повышает производительность)

for ($i=1; $i<1000000; $i++) {
  $a = get_one();
  $b = $a->v;
  $b = $a->k;
}

function get_one() {
  return new test(1,1);
}

class test {
  public $v;
  public $k;
  public function __construct($v, $k) {
    $this->v = $v;
    $this->k = $k;
  }
}

Ответ 6

Вы всегда можете проверить PHP-исходный код для функций микро-производительности.

Но на первый взгляд, не делать ['значение'] не будет быстрее, потому что PHP должен выполнить поиск по тому, где найти ['значение'], даже если вы хотите, чтобы поиск в хэш-таблице был O (1), это не гарантировано. Там, где вы используете Text-index, больше накладных расходов.

Если объект содержит только 1 переменную, к которой вам нужен доступ, то есть значение, при использовании объекта больше накладных расходов.

Ответ 7

Если массивы и классы имеют одинаковую производительность, я думаю, что использование объектов предопределенных классов для хранения/передачи бизнес-данных сделает нашу программу более логичной и более читаемой.

Сегодня, с современными идеями, такими как Eclipse, Netbean... очень удобно знать, какая информация содержит объекты (из предопределенного класса), но массивы не так.

Например: С массивом

function registerCourse(array $student) {
    // Right here I don't know how a $student look like unless doing a print_r() or var_dump()
 ....
}

С объектом

class Studen {
    private $_name, $_age;
    public function getAge() {}
    public function getName() {}
    ..
}

function registerCourse(Studen $student) {
    // Right here I just Ctrl+Space $student or click "Student" and I know I can get name or age from it
    ...
}

Ответ 8

скрипт magallanes @PHP 7.3.5

  • SomeClass Object является самым быстрым и легким.
  • Array 1.32x скорость. 2.70х памяти.
  • stdClass Object 1.65x скорость. 2.94x памяти.

Необработанная продукция:

arrays: 0.064794063568115
memory: 444920
Array (
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
arrays: 0.048975944519043
memory: 164512
SomeClass Object (
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)
arrays: 0.081161022186279
memory: 484416
stdClass Object (
    [aaa] => aaa
    [bbb] => bbb
    [ccc] => aaabbb
)