CODE COMPLETEを読みました – コードチューニング

前回と同様、コードコンプリート―完全なプログラミングを目指して (Microsoft PRESS) のまとめです。今回はコードチューニングに関して。

20年前の本なのですがコンピュータに関してのお約束というか基礎的な部分はほとんど変わっていないのでほとんどそのまま実用できると思います。

ループとスイッチング

for_if_test.php

<?php

print("悪い例の処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 0 〜 10000000までを足す処理をする
$flag  = true; // 計算するかどうかのフラグ
$sum = 0;
for ($i = 0; $i < 10000000; $i++) {
    if($flag){
        $sum += $i;
    }
}

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);
printf("Calculation result : %d <br />", $sum);


print("良い例の処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 0 〜 10000000までを足す処理をする
$flag  = true; // 計算するかどうかのフラグ
if($flag){
    $sum = 0;
    for ($i = 0; $i < 10000000; $i++) {
        $sum += $i;
    }
}

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);
printf("Calculation result : %d <br />", $sum);

これをCloud9のPHP環境で実行してみると、こんなかんじになります。

悪い例の処理
Max Memory Usage : 0.035 [MB]
Process Time : 1.88 [s]
Calculation result : 49999995000000
良い例の処理
Max Memory Usage : 0.034 [MB]
Process Time : 1.45 [s]
Calculation result : 49999995000000

ループと直接関係のない処理は、ループの外に積極的に出した方が高速化します。

ループの展開

for_unrolling_test.php

<?php

print("ループ展開前の処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 0 〜 10000000までを足す処理をする
$sum = 0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += $i;
}

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);
printf("Calculation result : %d <br />", $sum);


print("ループ展開後の処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 0 〜 10000000までを足す処理をする
$sum = 0;
for ($i = 0; $i < 10000000; $i+=5) {
    $sum += $i;
    $sum += $i + 1;
    $sum += $i + 2;
    $sum += $i + 3;
    $sum += $i + 4;
}

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);
printf("Calculation result : %d <br />", $sum);

結果はこんなかんじです。

ループ展開前の処理
Max Memory Usage : 0.035 [MB]
Process Time : 4.51 [s]
Calculation result : 49999995000000 
ループ展開後の処理
Max Memory Usage : 0.034 [MB]
Process Time : 2.22 [s]
Calculation result : 49999995000000 

うおーループの展開超はええ

高速な言語で書き直す

PHPよりもC、Cよりもアセンブラ言語のように、ベースとなっている高速な言語を使用することでパフォーマンスが改善します。

この本ではPascalからアセンブラで書き直す例をあげているのですが、同じようにPHPからCを呼び出す方法をやってみます。

<?php

print("PHPでの処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 0 〜 10000000までを足す処理をする
$sum = 0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += $i;
}

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Calculation result : %d <br />", $sum);
printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);


print("PHPからC言語を呼び出しての処理<br />");
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

$cmd = '/home/ubuntu/workspace/exec_test';
echo exec($cmd);

$maxMemoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Max Memory Usage : %.3f [MB]<br />", $maxMemoryUsage);
printf("Process Time : %.2f [s]<br />", $processTime);

exec_test.c

#include <stdio.h>

int main(void) {

    int i = 0;
    long sum = 0;
    /* 0 〜 10000000までを足す処理をする */
    for (i = 0; i < 10000000; i++) {
        sum += i;
    }

    printf("Calculation result : %ld <br />", sum);

    return 0;
}

Cはコンパイルしておき、実行します。結果は、

PHPでの処理
Calculation result : 49999995000000
Max Memory Usage : 0.032 [MB]
Process Time : 1.52 [s]
PHPからC言語を呼び出しての処理
Calculation result : 49999995000000
Max Memory Usage : 0.031 [MB]
Process Time : 0.03 [s]

C言語がとんでもなく早いことがよくわかりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です