PHP Objects vs Arrays — Performance comparison while iterating

前端 未结 10 1706
青春惊慌失措
青春惊慌失措 2020-11-27 11:25

I have a huge amount of PHP objects for a neural network for which I have to iterate over and perform some maths on. I was wondering if I would be better off using an associ

相关标签:
10条回答
  • 2020-11-27 11:57

    For anybody who is still interested in this question :) I ran Quazzle code on PHP 7.1 Ubuntu x64 and got this answer:

    arrays: 0.24848890304565
    
    memory: 444920
    
    Array
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    arrays: 0.23238587379456
    
    memory: 164512
    
    SomeClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    arrays: 0.24422693252563
    
    memory: 484416
    
    stdClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    

    Conclusion

    Array take 4(!) the memory than class object.
    Class object marginally faster.
    stdClass still evil © magallanes :)

    0 讨论(0)
  • 2020-11-27 11:59

    You haven't shown us the code for how $object->value works, as it could be that backend it is an array in which case theoretically using an array would be faster as it involves one less function call. The cost of doing the lookup will probably be huge compared to the function call. If it is a variable, there is going to be very little diffrence as objects and arrays in PHP have a very similar implementation.

    If you are looking at optimizations, you will need to profile to check where the majority of the time is being used. I suspect that changing objects to arrays will make no major difference.

    0 讨论(0)
  • 2020-11-27 11:59

    You can always check the PHP-source code for micro-performance-features like that.

    But at a first glance, no doing ['value'] will not be faster because PHP needs to do a Lookup on where to find ['value'] even thougn a hashtable lookup should be O(1), that's not guaranteed. There's more overhead when you use Text-index.

    If the object only contains 1 variables that you need to access which is value, there's more overhead in using an object.

    0 讨论(0)
  • 2020-11-27 12:00

    I used this code for "profiling" (1000 instances, 1000.000 reads/writes):

    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();
    

    It outputs in my LINUX hosting this stuff:

    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
    

    so in a conclusion: objects are slower even on PHP 5.2. Don't use objects unless you really need their oop features.

    0 讨论(0)
  • 2020-11-27 12:00

    If Arrays and Classs are the same performance, I think use objects of predefined classes for storing/passing business data would make our program more logic and the code more readability.

    Today, with modern ide like Eclipse, Netbean ... it's very convenient to know what info an objects (of predefined class) is carrying but arrays are not so

    Eg: With array

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

    With object

    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
        ...
    }
    
    0 讨论(0)
  • 2020-11-27 12:05

    Well I got curious today based off of @magallanes benchmark, so I expanded it a bit. I upped some of the for loops to really highlight the gaps between things. This is running on Apache 2.4, mod_php, and PHP 7.2.

    Here's a summary table to make the results easier:

    +---------------------------+---------+-----------------+
    |           Test            | Memory  |      Time       |
    +---------------------------+---------+-----------------+
    | Array                     | 2305848 | 9.5637300014496 |
    | stdClass                  | 2505824 | 11.212271928787 |
    | SomeClass                 |  963640 | 11.558017015457 | <-- *
    | AnotherClass              | 2563136 | 10.872401237488 |
    | SetterClass               |  905848 | 59.879059791565 |
    | SetterClassDefineReturn   |  905792 | 60.484427213669 |
    | SetterClassSetFromParam   |  745792 | 62.783381223679 |
    | SetterClassSetKeyAndParam |  745824 | 72.155715942383 |
    +---------------------------+---------+-----------------+
    * - Winner winner chicken dinner
    

    Below is the modified script. I wanted to test setting properties with methods and defining types. I was very surprised to find that using setter methods adds a significant hit to the code. Now granted this is a very very specific performance test where many apps will not even hit this. But if you have a site that handles 1000/reqs/second with 1000 classes that are used with 1000s of objects, you can see how this may affect performance.

    <?php
    
    set_time_limit(500);
    
    class SomeClass {
        public $aaa;
        public $bbb;
        public $ccc;
    }
        
    class AnotherClass {
    }
    
    class SetterClass {
        public $aaa;
        public $bbb;
        public $ccc;
    
        public function setAAA() {
            $this->aaa = 'aaa';
        }
    
        public function setBBB() {
            $this->bbb = 'bbb';
        }
    
        public function setCCC() {
            $this->ccc = $this->aaa.$this->bbb;
        }
    }
    
    class SetterClassDefineReturn {
        public $aaa;
        public $bbb;
        public $ccc;
    
        public function setAAA():void {
            $this->aaa = 'aaa';
        }
    
        public function setBBB():void {
            $this->bbb = 'bbb';
        }
    
        public function setCCC():void {
            $this->ccc = $this->aaa.$this->bbb;
        }
    }
    
    class SetterClassSetFromParam {
        public $aaa;
        public $bbb;
        public $ccc;
    
        public function setAAA(string $val): void {
            $this->aaa = $val;
        }
    
        public function setBBB(string $val): void {
            $this->bbb = $val;
        }
    
        public function setCCC(string $val): void {
            $this->ccc = $val;
        }
    }
    
    class SetterClassSetKeyAndParam {
        public $aaa;
        public $bbb;
        public $ccc;
    
        public function set(string $key, string $val): void {
            $this->{$key} = $val;
        }
    }
    
    function p($i) {
      echo '<pre>';
      print_r($i);
      echo '</pre>';
      echo '<hr>';
    }
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new SomeClass();
        for ($j=0; $j<5000; $j++) {
            $z->aaa = 'aaa';
            $z->bbb = 'bbb';
            $z->ccc = $z->aaa.$z->bbb;          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new AnotherClass();
        for ($j=0; $j<5000; $j++) {
            $z->aaa = 'aaa';
            $z->bbb = 'bbb';
            $z->ccc = $z->aaa.$z->bbb;          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new SetterClass();
        for ($j=0; $j<5000; $j++) {
            $z->setAAA();
            $z->setBBB();
            $z->setCCC();          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new SetterClassDefineReturn();
        for ($j=0; $j<5000; $j++) {
            $z->setAAA();
            $z->setBBB();
            $z->setCCC();          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new SetterClassSetFromParam();
        for ($j=0; $j<5000; $j++) {
            $z->setAAA('aaa');
            $z->setBBB('bbb');
            $z->setCCC('aaabbb');          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new SetterClassSetKeyAndParam();
        for ($j=0; $j<5000; $j++) {
            $z->set('aaa', 'aaa');
            $z->set('bbb', 'bbb');  
            $z->set('ccc', 'aaabbb');        
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = new stdClass();
        for ($j=0; $j<5000; $j++) {
            $z->aaa = 'aaa';
            $z->bbb = 'bbb';
            $z->ccc = $z->aaa.$z->bbb;          
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z); 
    
    
    $t0 = microtime(true);
    $arraysOf=[];
    $inicio=memory_get_usage(); 
    for ($i=0; $i<5000; $i++) {
        $z = [];
        for ($j=0; $j<5000; $j++) {
            $z['aaa'] = 'aaa';
            $z['bbb'] = 'bbb';
            $z['ccc'] = $z['aaa'].$z['bbb'];            
        }
        $arraysOf[]=$z;
    }
    $fin=memory_get_usage();    
    echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
    echo '<p>Memory: '.($fin-$inicio).'</p>';
    p($z);
    

    And here's the results:

    Time Taken (seconds): 11.558017015457
    
    Memory: 963640
    
    SomeClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    -----
    
    Time Taken (seconds): 10.872401237488
    
    Memory: 2563136
    
    AnotherClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 59.879059791565
    
    Memory: 905848
    
    SetterClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 60.484427213669
    
    Memory: 905792
    
    SetterClassDefineReturn Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 62.783381223679
    
    Memory: 745792
    
    SetterClassSetFromParam Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 72.155715942383
    
    Memory: 745824
    
    SetterClassSetKeyAndParam Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 11.212271928787
    
    Memory: 2505824
    
    stdClass Object
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    ----
    
    Time Taken (seconds): 9.5637300014496
    
    Memory: 2305848
    
    Array
    (
        [aaa] => aaa
        [bbb] => bbb
        [ccc] => aaabbb
    )
    
    
    0 讨论(0)
提交回复
热议问题