9

これは単純なプログラミングの質問です。PHP がforeachループ中に配列のコピーと設定解除をどのように処理するかについての知識が不足しているためです。こんな感じです。変更したい方法でフォーマットされた外部ソースからの配列があります。簡単な例は次のとおりです。

$myData = array('Key1' => array('value1', 'value2'));

しかし、私が欲しいのは次のようなものです:

$myData = array([0] => array('MyKey' => array('Key1' => array('value1', 'value2'))));

だから私は最初のものを取り、$myData2番目のようにフォーマットします$myData。私は自分のフォーマットアルゴリズムに全く問題ありません。私の質問は、これらの配列が少し扱いに​​くくなる可能性があるため、メモリを節約する方法を見つけることにあります。したがって、foreachループ中に現在の配列値を新しい形式にコピーしてから、元の配列から作業中の値を設定解除します。例えば:

$formattedData = array();
foreach ($myData as $key => $val) {
    // do some formatting here, copy to $reformattedVal

    $formattedData[] = $reformattedVal;

    unset($myData[$key]);
}

unset()ここで良いアイデアへの呼びかけはありますか?つまり、データをコピーして元の値が不要になったので、メモリを節約できますか? または、後続のコードでデータを参照していないため、PHP は自動的にデータをガベージ コレクションしますか?

コードは正常に実行され、これまでのところ、パフォーマンスの違いをテストするにはデータセットのサイズがごくわずかでした。後で奇妙なバグやCPUヒットに備えているのかどうかはわかりません.

洞察をありがとう。
-sR

4

5 に答える 5

4

Optimization Clubのルールを覚えておいてください:

  1. 最適化クラブの最初のルールは、最適化しないことです。
  2. 最適化クラブの 2 つ目のルールは、測定せずに最適化しないことです。
  3. アプリが基になるトランスポート プロトコルよりも高速に実行されている場合、最適化は終了しています。
  4. 一度に 1 つの要因。
  5. マーケットロイドもマーケットロイドのスケジュールもありません。
  6. 必要な限り、テストは続行されます。
  7. これが Optimization Club での最初の夜である場合は、テスト ケースを作成する必要があります。

ここでは、ルール 1 と 2 が特に重要です。最適化する必要があることを知っていない限り、また最適化の必要性を測定していない限り、それを行うべきではありません。unset を追加すると、実行時のヒットが追加され、将来のプログラマーがなぜそれを行うのかがわかります。

ほっといて。

于 2011-01-12T22:52:39.530 に答える
4

foreach演算子を使用してループ内の変数への参照を使用します&foreachこれにより、反復処理のためにメモリ内に配列のコピーを作成する必要がなくなります。

編集: Artefactoで指摘されているように、変数の設定を解除すると、元の変数への参照の数が減少するだけなので、保存されるメモリは変数の値ではなくポインターのみになります。奇妙に参照を使用すると、おそらく値が参照される代わりに新しいメモリ位置にコピーされるため、実際には総メモリ使用量が増加します。

配列が参照されない限り、 foreach は、配列自体ではなく、指定された配列のコピーを操作します。foreach には、配列ポインターにいくつかの副作用があります。foreach の実行中または実行後に、リセットせずに配列ポインターに依存しないでください。

使用memory_get_usage()しているメモリの量を特定するために使用します。

メモリの使用量と割り当てに関する適切な記事がここにあります

これは、メモリ割り当てを確認するのに役立つテスト コードです。コメント行のコメントを外して、さまざまなシナリオでの合計メモリ使用量を確認してください。

echo memory_get_usage() . PHP_EOL;
$test = $testCopy = array();
$i = 0;
while ($i++ < 100000) {
    $test[] = $i;
}
echo memory_get_usage() . PHP_EOL;
foreach ($test as $k => $v) {
//foreach ($test as $k => &$v) {
    $testCopy[$k] = $v;
    //unset($test[$k]);
}
echo memory_get_usage() . PHP_EOL;
于 2011-01-12T21:23:05.453 に答える
3

ループ内でテキスト (xml) ファイルの行を処理しているときに、メモリが不足していました。同様の状況にある人にとって、これは私にとってはうまくいきました:

while($data = array_pop($xml_data)){
     //process $data
}
于 2013-02-01T16:48:09.743 に答える
2

「フォーマット」の任意の時点で、次のようなことを行う場合:

$reformattedVal['a']['b'] = $myData[$key];

次にunset($myData[$key]);、変数の参照カウントを減らすだけであるため、メモリに関しては無関係です。これは、現在2つの場所($myData[$key]との内部$reformattedVal['a']['b'])に存在しています。実際には、元の配列内の変数にインデックスを付けるメモリを節約できますが、それはほとんど何もありません。

于 2011-01-12T21:23:59.003 に答える
0

イテレータ内で配列を変更することはできないため、参照によって要素にアクセスしていない限り、設定を解除しても何も起こりません。

とは言うものの、反復しているコレクションを変更することは一般的に悪い習慣と考えられています。より良いアプローチは、ソース配列を小さなチャンクに分割し (一度にソース データの一部のみをロードすることによって)、これらを処理することです。配列全体の「チャンク」を設定解除します。

于 2011-01-12T21:22:05.090 に答える