No.5ベストアンサー
- 回答日時:
参照が速くない大きな理由の一つは、
$a =& $b;
$c = $a; // ここで値のコピーが発生と思われる
と同じことが、組み込み関数をコールするところで起こってしまうため、
参照の意味が無くなることが多いことだと思います。
提示していただいたベンチマークのコードだと、
is_array, implodeのところで$dataがコピーされていると思います。
関数をコールする都度これが起こると思われるので、
それが速度低下の大きな原因だと思います。
やはり「参照渡しそのものが遅い」わけではないと思います。
ただ、上の理由から、余程注意しないと、「参照渡しを使うと全体として遅くなる」
という結果を招くことは確かだと思います。
また、場合によってはガベコレの影響も大きいようなので、
ベンチマークの時は注意する必要があると思います。
(下のサンプルのガベコレのところを変えるだけで随分違います)
下は本当に差が出るサンプルです。
<?php
// 配列 $array に $data をプッシュしたものを返す関数
function pushed($array, $data)
{
// ここで$arrayを操作するため、
// 実際に$arrayのデータをコピーする必要が生じる。
// ここをコメントアウトすれば、
// $arrayが値渡しであっても、
// $arrayの中身のコピーは起こらない。
$array []= $data;
return $array;
}
// 配列 $array に $data をプッシュする関数
function push(&$array, $data)
{
$array []= $data;
}
$n = 10;
$time = 0;
for ($i = 0; $i < $n; $i++) {
$dat = range(0,99999);
$res = null; // GCの時間を除外するため、ここでGCを起こす
$t = microtime(true);
$res = pushed($dat, null);
$time += microtime(true) - $t;
}
echo "V={$time}\n";
$time = 0;
for ($i = 0; $i < $n; $i++) {
$dat = range(0,99999);
$t = microtime(true);
push($dat, null);
$time += microtime(true) - $t;
}
echo "R={$time}\n";
?>
No.4
- 回答日時:
ベンチマークに使ったコードを実際に見せていただければ、もっと詳しいことが分かると思います。
この回答への補足
function Ufun_implode_recursive ($istr, $data) {
if (is_array ($data)) {
while (list ($key,) = each ($data)) {
$data[$key] = Ufun_implode_recursive ($istr, $data[$key]);
}
$data = implode ($istr, $data);
}
return $data;
}
と
function Ufun_implode_recursive ($istr, &$data) {
if (is_array ($data)) {
while (list ($key,) = each ($data)) {
Ufun_implode_recursive ($istr, $data[$key]);
}
$data = implode ($istr, $data);
}
}
です。
他の2つに関しましては余り意味が無いので既に破棄しています。
No.3
- 回答日時:
状況にもよるかと思いますが、
PHPの場合の参照の場合、参照カウンタがそれぞれ作られて、参照されている数の管理をしています。
なので、その分のオーバーヘッドがあって、単純なint のコピーで済む場合より遅い場合があるのかも知れません。
No.2
- 回答日時:
私の実感だと、やはり参照渡しの方が速いと思います。
恐らく、PHPで実際にコピー操作が起こるのは、本当にそれが必要になったとき、だと思います。
つまり、$a = $b; も $a =& $b; とやったとも、処理は殆ど同じで、前者であっても実際のデータのコピーは起こらないのだと思います。
(ソースコードレベルで言うと、どちらもzvalue_value共用体のシャローコピーでしかないということ)
データのディープコピーが起こるのは、
その後に例えば、$a .= 'B'; とかしたときなど、本当に $a の実体が必要になったとき、だと思います。
このあたりの事情がベンチマークを狂わせているのではないかと思います。
実際に代入されている値を変更するような動作を大量に行っても
参照渡しのほうが遅いのでベンチマークが翻弄されているだけではないと思います。
誤差と見る事も出来ないわけではない大きさではないですが
挙動の違うロジックで同様の結果が出た為誤差では無いのではないかと思うのです。
No.1
- 回答日時:
それが真実かどうかはべつとして
そういう風につくられているからでしょう。
ベンチマークをとれば実証はできますが、
ソースを追っかけて検証することはかなり難しく
それをプログラム的に説明されても、理解できるとは
思いませんが・・・。
(逆にそれが理解できるならご自身で検証してください)
また結果としてその命題が真実であっても、その
点がボトルネックになるプログラムを書くこと自体がない
でしょうし、もし書くことがあってそれが致命的で
あっても傾向がわかっているなら対処のしようもあるので、
なにも問題がないかと。
ありがとうございます。
http://rio.st/archives/2003/12/php_tips_2.html
の記事が事実なのか検証の為に
関数が再帰的に呼び出しその時の引数を参照渡しで渡すものと値渡しで渡すもの
for文で変数を配列に参照渡しでコピーするもの値渡しでコピーするもの
要素数10*10*10の3次元配列をimplodeで結合し全ての要素を結合する際に参照渡しで行うものと値渡しで行うもの
を作成し実際にベンチマークを行いました。
Solaris 10+Apache2.0.52+PHP4.3.2
Fedora Core 5(Kernel 2.6.17)+Apache 2.2.3+PHP 5.1.4
Windows XP+Apache 2.2.3+PHP 5.1.4
以上の環境での100回の結果を大きい方と小さい方から20個計40個を除去し
残り60個の平均が参照渡しの方が約2~5%遅かった為に疑問に思った次第です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語の配列をPush(追加)する...
-
MYSQLとPHPによって取得する多...
-
C言語 最大値と最小値を求めて...
-
タグの中身だけを取り出す正規
-
Smarty 三次元配列を使いたい
-
2次元配列CSVのソート
-
PHPは何故値渡しより参照渡しの...
-
行列
-
php で1から100までの素数の表...
-
配列の要素(value)に、変数を...
-
verilogで、配列の一部をタスク...
-
file_existsでファイル名の部分...
-
foreachのなかで次のキーを参照...
-
$_SESSIONに二次元配列を使える...
-
ヒアドキュメントの中のfor文
-
ファイルから指定行数分だけ読...
-
ラジオボタンをランダムに表示...
-
URLのサブドメインとドメイン部...
-
PHPのPOSTでの半角スペース
-
【Smarty】foreach関数やsectio...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語の配列をPush(追加)する...
-
行列
-
np.stack()とnp.array()の違い
-
2次元配列CSVのソート
-
配列の要素(value)に、変数を...
-
C言語 最大値と最小値を求めて...
-
STLのvectorで作った配列をメン...
-
特定の文からメールアドレスの...
-
CArrayのソート
-
MYSQLとPHPによって取得する多...
-
ファイルの書き込みについて教...
-
verilogで、配列の一部をタスク...
-
CArrayの要素としてCStringArra...
-
array_intersectで空欄を比較し...
-
pg_copy_fromの使い方について...
-
構造体を動的に確保&解放
-
同一列内のセルを結合して表示...
-
cakephpでのトランザクション処...
-
c言語 単位行列
-
読み(あ行~わ行)ごとに分け...
おすすめ情報