2012-05-23 7 views
9

なぜ、グローバルPHPの配列変数を使用して対の特性として、オブジェクトの配列のを使用した場合の主要なパフォーマンス上の問題がありますか?PHPオブジェクトの配列は、グローバル配列がそうしながら、直線的ではないのか?

この問題をベンチマークするために、stdClassをノードとしてますます大きくなる配列を格納する次のベンチマークを作成しました。クラスの配列プロパティを使用して2つのテストを実行しました。今

Testing Objects 
Array Size 1000 
2 milliseconds to perform 
Array Size 2000 
3 milliseconds to perform 
Array Size 4000 
6 milliseconds to perform 
Array Size 8000 
12 milliseconds to perform 
Array Size 16000 
35 milliseconds to perform 
Array Size 32000 
97 milliseconds to perform 
Array Size 64000 
246 milliseconds to perform 
Array Size 128000 
677 milliseconds to perform 
Array Size 256000 
2271 milliseconds to perform 
Array Size 512000 
9244 milliseconds to perform 
Array Size 1024000 
31186 milliseconds to perform 
Array Size 2048000 
116123 milliseconds to perform 
Array Size 4096000 
495588 milliseconds to perform 
================ 
Testing Array 
Array Size 1000 
1 milliseconds to perform 
Array Size 2000 
2 milliseconds to perform 
Array Size 4000 
4 milliseconds to perform 
Array Size 8000 
8 milliseconds to perform 
Array Size 16000 
28 milliseconds to perform 
Array Size 32000 
61 milliseconds to perform 
Array Size 64000 
114 milliseconds to perform 
Array Size 128000 
245 milliseconds to perform 
Array Size 256000 
494 milliseconds to perform 
Array Size 512000 
970 milliseconds to perform 
Array Size 1024000 
2003 milliseconds to perform 
Array Size 2048000 
4241 milliseconds to perform 
Array Size 4096000 
14260 milliseconds to perform 

オブジェクトの明らかなオーバーヘッドは、オブジェクト配列プロパティのスケールがひどく、時には3取って自分自身を呼び出す以外にも - 長い4回:

テストコード

ini_set('memory_limit', '2250M'); 
class MyTest { 
    public $storage = []; 
    public function push(){ 
     $this->storage[] = [new stdClass()]; 
    } 
} 

echo "Testing Objects".PHP_EOL; 
for($size = 1000; $size < 5000000; $size *= 2) { 
    $start = milliseconds(); 
    for ($a=new MyTest(), $i=0;$i<$size;$i++) { 
     $a->push(); 
    } 
    $end = milliseconds(); 
    echo "Array Size $size".PHP_EOL; 
    echo $end - $start . " milliseconds to perform".PHP_EOL; 
} 
echo "================".PHP_EOL; 
echo "Testing Array".PHP_EOL; 
for($size = 1000; $size < 5000000; $size *= 2) { 
    $start = milliseconds(); 
    for ($a=[], $i=0;$i<$size;$i++) { 
     $a[] = [new stdClass()]; 
    } 
    $end = milliseconds(); 
    echo "Array Size $size".PHP_EOL; 
    echo $end - $start . " milliseconds to perform".PHP_EOL; 
} 

そして衝撃的な結果配列は大きくなりますが、これは標準のグローバル配列変数の場合には当てはまりません。

この問題に関する任意の考えや答えは、これはPHPエンジンで可能なバグですか?

+0

これは配列の問題ですが、OOPオーバーヘッドになる可能性があります。オブジェクト内にその配列を構築しているためです(OOPオーバーヘッドがたくさんあります)。一時的にそのオブジェクトメンバーを標準グローバル変数に置き換えると、パフォーマンスはまったく変わりますか? –

+0

この問題を実際の問題に還元して、prggmrの全体を残しておいてもらえますか?それは質問を理解しにくくする。 – NikiC

+0

@MarcB変更がありますが、それは重要な変更ではありません(真の '' $ this - > _ event_history [] = [true] ''のみが10秒間に1秒あたり9532を出力するように履歴を変更してください)。 – Nick

答えて

6

私はPHP 5.3.9であなたのコードをテストしました。これを行うには[]array()に翻訳しなければなりませんでした。また、$a=new MyTest($size)から$mytest=new MyTest($size)にあなたの行#12を修正しなければなりませんでした(コンストラクタ引数は無視されます。あなたの5000000のと、

echo "================".PHP_EOL; 
echo "Testing Function".PHP_EOL; 
for($size = 1000; $size < 1000000; $size *= 2) { 
    $start = milliseconds(); 
    for ($a=array(), $i=0;$i<$size;$i++) { 
     my_push($a); 
    } 
    $end = milliseconds(); 
    echo "Array Size $size".PHP_EOL; 
    echo $end - $start . " milliseconds to perform".PHP_EOL; 
    echo "memory usage: ".memory_get_usage()." , real: ".memory_get_usage(true).PHP_EOL; 
} 

function my_push(&$a) 
{ 
    $a[] = array(new stdClass()); 
} 

私は同じポイントであなたのループにメモリ使用量のラインを追加しました(より一貫性メモリのログを取得するために)、オブジェクトケースの後unset($mytest);を追加した、とも置き換え:私はまた、このコードを追加しました私は2GBのRAMしか持っていないので1000000です。これは私が得たものです:あなたが見ることができるように

Testing Objects 
Array Size 1000 
2 milliseconds to perform 
memory usage: 1666376 , real: 1835008 
Array Size 2000 
5 milliseconds to perform 
memory usage: 2063280 , real: 2097152 
Array Size 4000 
10 milliseconds to perform 
memory usage: 2857008 , real: 2883584 
Array Size 8000 
19 milliseconds to perform 
memory usage: 4444456 , real: 4718592 
Array Size 16000 
44 milliseconds to perform 
memory usage: 7619392 , real: 8126464 
Array Size 32000 
103 milliseconds to perform 
memory usage: 13969256 , real: 14417920 
Array Size 64000 
239 milliseconds to perform 
memory usage: 26668936 , real: 27262976 
Array Size 128000 
588 milliseconds to perform 
memory usage: 52068368 , real: 52690944 
Array Size 256000 
1714 milliseconds to perform 
memory usage: 102867104 , real: 103546880 
Array Size 512000 
5452 milliseconds to perform 
memory usage: 204464624 , real: 205258752 
================ 
Testing Array 
Array Size 1000 
1 milliseconds to perform 
memory usage: 18410640 , real: 20709376 
Array Size 2000 
4 milliseconds to perform 
memory usage: 18774760 , real: 20709376 
Array Size 4000 
7 milliseconds to perform 
memory usage: 19502976 , real: 20709376 
Array Size 8000 
13 milliseconds to perform 
memory usage: 20959360 , real: 21233664 
Array Size 16000 
29 milliseconds to perform 
memory usage: 23872176 , real: 24379392 
Array Size 32000 
61 milliseconds to perform 
memory usage: 29697720 , real: 30146560 
Array Size 64000 
124 milliseconds to perform 
memory usage: 41348856 , real: 41943040 
Array Size 128000 
280 milliseconds to perform 
memory usage: 64651088 , real: 65273856 
Array Size 256000 
534 milliseconds to perform 
memory usage: 111255536 , real: 111935488 
Array Size 512000 
1085 milliseconds to perform 
memory usage: 204464464 , real: 205258752 
================ 
Testing Function 
Array Size 1000 
357 milliseconds to perform 
memory usage: 18410696 , real: 22544384 
Array Size 2000 
4 milliseconds to perform 
memory usage: 18774768 , real: 22544384 
Array Size 4000 
9 milliseconds to perform 
memory usage: 19503008 , real: 22544384 
Array Size 8000 
17 milliseconds to perform 
memory usage: 20959392 , real: 22544384 
Array Size 16000 
36 milliseconds to perform 
memory usage: 23872208 , real: 24379392 
Array Size 32000 
89 milliseconds to perform 
memory usage: 29697720 , real: 30146560 
Array Size 64000 
224 milliseconds to perform 
memory usage: 41348888 , real: 41943040 
Array Size 128000 
529 milliseconds to perform 
memory usage: 64651088 , real: 65273856 
Array Size 256000 
1587 milliseconds to perform 
memory usage: 111255616 , real: 111935488 
Array Size 512000 
5244 milliseconds to perform 
memory usage: 204464512 , real: 205258752 

は、関数呼び出しの内部配列に追加して、あなたのオリジナルのメソッド呼び出しの内部でそれをやってとほぼ同じくらいの費用がかかる(と同じ非線形挙動を持っています)。一つのことは確かに言うことができます。

それはCPU時間を食べる関数呼び出しです!

非線形動作に関しては、実際には特定のしきい値を超えてのみ明らかになります。 3つのケースはすべて同じメモリ動作をしますが(gargabeコレクションが不完全であるため、これは「プレーン・アレイ」と「関数内の配列」の間でのみ明らかです)、このメソッドは「メソッド内の配列」であり、同じ実行時間の動作を持つケースを関数内に配列します。つまり、時間の非直線的な増加を引き起こすのは関数呼び出しです。

関数呼び出し中のデータの量は、その持続時間に影響を与えます。これを確認するには

私は(同様の総実行時間を得るために)5000000と$a[0]、すべての1000000を持つすべて$a[]を交換し、この出力を取得した時間は今、ほぼ完全に線形であるか

Testing Objects 
Array Size 1000 
2 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 2000 
4 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 4000 
8 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 8000 
15 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 16000 
31 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 32000 
62 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 64000 
123 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 128000 
246 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 256000 
493 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 512000 
985 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 1024000 
1978 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 2048000 
3965 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
Array Size 4096000 
7905 milliseconds to perform 
memory usage: 1302672 , real: 1572864 
================ 
Testing Array 
Array Size 1000 
1 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 2000 
3 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 4000 
5 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 8000 
10 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 16000 
20 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 32000 
40 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 64000 
80 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 128000 
161 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 256000 
322 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 512000 
646 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 1024000 
1285 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 2048000 
2574 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 4096000 
5142 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
================ 
Testing Function 
Array Size 1000 
1 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 2000 
4 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 4000 
6 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 8000 
14 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 16000 
26 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 32000 
53 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 64000 
105 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 128000 
212 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 256000 
422 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 512000 
844 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 1024000 
1688 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 2048000 
3377 milliseconds to perform 
memory usage: 1302464 , real: 1572864 
Array Size 4096000 
6814 milliseconds to perform 
memory usage: 1302464 , real: 1572864 

注意。もちろん、配列のサイズは1に固定されています。 3つのケースの実行時間の差異が以前よりもどのように顕著でないかにも注意してください。最も内側の操作はすべてのケースで同じであることを忘れないでください。

私はこれを完全に説明しようとはしません(関数呼び出しでのガーガーベーコレクション?メモリの断片化?...?)、私はここでも自分のために役立つ情報を収集したと思いますあまりにも。

+1

'unset($ mytest);を追加していない場合でも、すべてが約10%遅くなります。 – sanmai

+0

大きな答えは...これは実際にはPHPソースに潜入する必要があります。なぜなら、このような使用時間の大幅な短縮を引き起こすコンテキスト間の変数にアクセスする際に何かが起こっていると思われ、 (彼らはそうではありませんか?)データのサイズは重要ではありません。追加されたデータ以外に何も書かれていないからです。あるいは、これは開発者の決定の一部との遭遇に過ぎませんおそらく気づかれなくなった言語を彼らが開発したときに取った... – Nick

2

私はそうこれが答えよりも観測の詳細です、すべてのコメントでこれを投稿することはできません。 SplObjectStorageはかなり遅いように見えます。また、array_pushは$ array [] = 'item'よりずっと高速です。

免責事項:ずさんなコードのための謝罪:)

<?php 

$time = microtime(); 
$time = explode(' ', $time); 
$time = $time[1] + $time[0]; 
$start = $time; 

$iteration = 10000; 

switch ($_REQUEST['test']) 
{ 
    case 1: 
     $s = new SplObjectStorage(); 

     for ($i = 0; $i < $iteration; $i++) { 
      $obj = new stdClass; 
      $s[$obj] = 'test'; 
     } 
     break; 
    case 2: 

     $s = array(); 
     for ($i = 0; $i < $iteration; $i++) { 
      $obj = new stdClass; 
      $s[$i] = $obj; 
     } 
     break; 

    case 3: 
     class Test { 
      public $data = array(); 
     } 
     $s = new Test; 
     for ($i = 0; $i < $iteration; $i++) { 
      $obj = new stdClass; 
      $s->data[] = $obj; 
     } 
     break; 

    case 4: 
     class Test { 
      public static $data = array(); 
     } 
     $s = new Test; 
     for ($i = 0; $i < $iteration; $i++) { 
      $obj = new stdClass; 
      $s->data[] = $obj; 
     } 
     break; 
    case 5: 
     class Test { 
      public $data = array(); 
     } 
     $s = new Test; 
     for ($i = 0; $i < $iteration; $i++) { 
      $obj = new stdClass; 
      array_push($s->data, $obj); 
     } 
     break; 
    default: 
     echo 'Type in ?test=#'; 
} 

$time = microtime(); 
$time = explode(' ', $time); 
$time = $time[1] + $time[0]; 
$finish = $time; 
$total_time = round(($finish - $start), 6); 
echo 'Page generated in '.$total_time.' seconds.'; 
+1

私は理由がわからないので、合理的な回答と思われます。 –

+0

@AlixAxel:おそらく答えではないからでしょう。コードがPHPの特性を調べるのに便利だと思われるので、私はダウン投票していません。 – wallyk

関連する問題