13

次の整数の配列があるとします。

array(1, 2, 1, 0, 0, 1, 2, 4, 3, 2, [...] );

整数は最大100万エントリになります。ハードコーディングされる代わりに、事前に生成され、JSON形式のファイル(サイズは約2MB)に保存されています。これらの整数の順序は重要です。一貫性があり、同じインデックスで常に同じ値を持つ必要があるため、毎回ランダムに生成することはできません。

このファイルを後でPHPで読み戻す場合(たとえばfile_get_contents+を使用json_decode)、配列を元に戻すだけで700〜900ミリ秒かかります—「わかりました」「json_decode約200万文字を解析する必要があるので、おそらく妥当だと思いました。キャッシュしましょう」 。APCはそれを約68MBのエントリにキャッシュしますが、おそらく通常のzvalsは大きいです。ただし、このアレイをAPCから取得するには、600ミリ秒もかかりますが、これはまだあまりにも多くのことです。

編集:APCは、シリアル化/逆シリアル化してコンテンツを保存および取得します。コンテンツは、100万個のアイテム配列を使用すると、時間と手間がかかります。

だから質問:

  • データストアやメソッドに関係なく、PHPで100万エントリの配列をロードする場合、このレイテンシを期待する必要がありますか?私が理解している限り、APCはzval自体を格納するので、理論的にはAPCからの取得は可能な限り高速である必要があります(解析、変換、ディスクアクセスなし)

  • なぜAPCは、一見単純に見えるものに対して非常に遅いのですか?

  • PHPを使用して100万エントリの配列を完全にメモリにロードする効率的な方法はありますか?RAMの使用量が問題ではないと仮定します。

  • インデックスに基づいてこの配列のスライスのみにアクセスし(たとえば、インデックス15からインデックス76にチャンクをロードする)、実際に配列全体をメモリに保存しない場合(はい、これは正しい方法であると理解していますが、すべての側面を知りたい)、完全なアレイのための最も効率的なデータストアシステムは何でしょうか?明らかにRDBMではありません。redisを考えていますが、他のアイデアを聞いていただければ幸いです。

4

4 に答える 4

3

整数がすべて0〜15であるとします。次に、バイトごとに2つを格納できます。

<?php
$data = '';
for ($i = 0; $i < 500000; ++$i)
  $data .= chr(mt_rand(0, 255));

echo serialize($data);

走る:php ints.php > ints.ser

これで、0から15までの1,000,000個のランダムな整数を含む500000バイトの文字列を含むファイルができました。

ロードするには:

<?php
$data = unserialize(file_get_contents('ints.ser'));

function get_data_at($data, $i)
{
  $data = ord($data[$i >> 1]);

  return ($i & 1) ? $data & 0xf : $data >> 4;
}

for ($i = 0; $i < 1000; ++$i)
  echo get_data_at($data, $i), "\n";

私のマシンのロード時間は約.002秒です。

もちろん、これはあなたの状況に直接当てはまらないかもしれませんが、100万エントリの肥大化したPHP配列よりもはるかに高速です。率直に言って、PHPでこれほど大きな配列を持つことは、決して適切な解決策ではありません。

これが適切な解決策であるとは言いませんが、パラメータに適合していれば間違いなく実行可能です。

配列に0〜255の範囲の整数が含まれている場合は、パッキングを削除して、としてデータにアクセスできることに注意してくださいord($data[$i])。その場合、文字列の長さは1Mバイトになります。

最後に、のドキュメントによるとfile_get_contents()、phpはファイルをメモリマップします。その場合、最高のパフォーマンスは、生のバイトをファイルにダンプし、次のように使用することです。

$ints = file_get_contents('ints.raw');
echo ord($ints[25]);

ints.rawこれは、が正確に100万バイトの長さであることを前提としています。

于 2012-07-28T17:46:24.290 に答える
2

APCはシリアル化されたデータを保存するため、APCからロードバックされるときにシリアル化を解除する必要があります。それはあなたのオーバーヘッドがあるところです。

それをロードする最も効率的な方法は、PHPとしてファイルに書き込み、include()を使用することですが、100万個の要素を含む配列では、どのレベルの効率も得られません...膨大な量のメモリが必要です。ロードには時間がかかります。これがデータベースが発明された理由ですが、データベースの問題は何ですか?

編集

シリアル化/逆シリアル化を高速化したい場合は、igbinary拡張機能を確認してください

于 2012-07-28T15:20:33.900 に答える
1

一貫性があり、同じインデックスで常に同じ値を持つ必要があるため、毎回ランダムに生成することはできません。

疑似乱数を読んだことがありますか?この問題に対処するシードと呼ばれるこの小さなものがあります。

また、オプションと主張のベンチマークを行います。file_get_contentsとjson_decodeのタイミングを合わせましたか?ここでは、ストレージとアクセスのコストの間でトレードオフを行う必要があります。例えば。数値が0..9(または0..255)の場合は、2Mbの文字列に格納して、これにアクセス関数を使用する方が簡単な場合があります。2Mbは、FSまたはAPCのどちらからでもより高速にロードされます。

于 2012-07-28T15:32:24.760 に答える
1

マークが言ったように、これがデータベースが作成された理由です-通常の使用パターンに基づいてデータを効果的に検索(および操​​作できますが、必要ない場合もあります)できるようにするためです。また、配列を使用して独自の検索を実装するよりも高速になる場合があります。アレイにアクセスするたびに、(シリアル化前の)2〜300MBのデータがシリアル化および非シリアル化されることについて話していると思います。

速度を上げたい場合は、配列の各要素を個別に割り当ててみてください。関数呼び出しのオーバーヘッドを、シリアル化に費やした時間と交換することができます。これを独自の拡張機能で拡張して、データセットを小さな取得インターフェイスでラップすることもできます。

zvalを直接保存できない理由は、内部状態が含まれているためだと思います。また、変数シンボルテーブルを前のテーブルにポイントするだけでは不十分です。

于 2012-07-28T15:36:39.190 に答える