2

[ここに編集された OP は短いバージョンです]

ファイルをループして内容を読み取ってから書き込むと、関数が失敗します。メモリの問題のようでした。これは私が試した3つのバージョンです。

最初にこれを試しました:

$file = new SplFileObject($this->getDirectoryPath() . $this->getFileName(), "a+");
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY);

if ($this->exists()) {
    foreach ($file as $line) {
        $tempArray = unserialize($line);
        if ($tempArray['Key'] == $arrayOfData['Key']) {
            foreach ($totalsToBeAdded as $key) {
                $arrayOfData[$key] += $tempArray[$key];
            }
        }
    }
}

$tempString = serialize($arrayOfData);

$file->fwrite("$tempString\r\n");

$this->numLines++;

それから私はこれを試しました:

$file = new SplFileObject($this->getDirectoryPath() . $this->getFileName(), "a+");
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY);

if ($this->exists()) {
    while (!$file->eof()) {
        $tempArray = unserialize($file->current());
        if ($tempArray['PartNumber'] == $arrayOfData['PartNumber']) {
            foreach ($totalsToBeAdded as $key) {
                $arrayOfData[$key] += $tempArray[$key];
            }
        }

        $file->next();
    }
}

$tempString = serialize($arrayOfData);

$file->fwrite("$tempString\r\n");

$this->numLines++;

そして最後に、SplFileObject を放棄し、通常の fopen などを使用しました。

$handle = fopen($this->getDirectoryPath() . $this->getFileName(), "a+");

if ($this->exists()) {
    while (false !== ($line = fgets($handle))) {
        $tempArray = unserialize(trim($line));
        if ($tempArray['Key'] == $arrayOfData['Key']) {
            foreach ($totalsToBeAdded as $key) {
                $arrayOfData[$key] += $tempArray[$key];
            }
        }
    }
}

$tempString = serialize($arrayOfData);
fwrite($handle, "$tempString\r\n");
fclose($handle);
$this->numLines++;

詳細については編集してください:

ファイルを 1 行ずつステップ実行するときに、PHP の基になるコードがイテレータに配列を使用しているかどうかに興味がありました。

また、ファイルの構築が開始されます。約 500 ~ 600k になるまで書き込んでから死ぬのを見ることができます。

最終的なファイル サイズは約 10 MB になります。

最後の更新:

これは機能します(ファイルのオープンと読み取りの欠如に注意してください):

public function writeUnique($arrayOfData, $totalsToBeAdded) {  
        $tempArray = array();

        $handle = fopen($this->fullPath, "a+");

        $tempString = serialize($arrayOfData);
        fwrite($handle, "$tempString\r\n");
        fclose($handle);
        $this->numLines++;
}

これが壊れている間(実行中のすべてがファイル全体をループしてからファイルに書き込むことに注意してください):

public function writeUnique($arrayOfData, $totalsToBeAdded) {  
        $tempArray = array();

        $handle = fopen($this->fullPath, "a+");

        if ($this->exists()) {
            while (false !== ($line = fgets($handle))) {

            }
        }

        $tempString = serialize($arrayOfData);
        fwrite($handle, "$tempString\r\n");
        fclose($handle);
        $this->numLines++;
}

更新番号 3:

私は今これをテストしました:

public function writeUnique($arrayOfData, $totalsToBeAdded) {

    $handle = fopen($this->fullPath, "a+");

    if ($this->exists()) {
        while (false !== ($line = fgets($handle))) {

        }
    }

    $tempString = serialize($arrayOfData);
//        fwrite($handle, "$tempString\r\n"); Commented out the writing.
    fclose($handle);
    $this->numLines++;
}

これはうまくいきました。障害、メモリエラーなどはありません。

したがって、大きなファイルの同じ行を再読み取りする反復の問題であるか、関数の書き込み部分が何らかの方法で読み取り関数のつま先を踏んでいるようです..正直に言って意味がありません. 誰もが私の配列に関係があると考えていたことを知っています。しかし、私はすべてのロジックをほとんど取り除いてしまい、大きなファイルを読み書きしようとしています。

4

2 に答える 2

0

それで、私は最終的に故障して、このファイルでphpが完了する必要があるループの数を計算するために計算を行いました。その数は8,788,338,000,000回です。

これにより、PHP がタイムアウトしました。タイムアウトしないようにするには、このコード行を追加する必要がありました。

set_time_limit(0); // ignore php timeout

これで、一時ファイルをすべて読み取り、1 行ずつ解析できるようになりました。ただし、大きなファイル (10 mb 以上) では、これまでのところ関数を完了するのに 1 時間以上かかります (一時ファイルが大きくなっているのを見ると、関数はまだ実行されています)。

速度が本質である場合、LARGE データ セットを一時 SQL テーブルに格納する方がおそらく良いという結論に達しました。これは以前は私にとって選択肢ではありませんでしたが、今ではそれを許可する権限で問題を強制しています. 最悪の場合、これで少なくとも実行できるようになります。

警告: これにより、無限ループが永久に実行され、サーバーが停止する可能性があります。試行する前に、UNIX を介してプロセスを強制終了する方法を知っていることを確認してください。

于 2012-11-05T16:18:14.810 に答える
0

試す:

if ($this->exists()) {
    while (false !== ($line = fgets($handle))) {
        $tempArray = unserialize(trim($line));
        unset($line);
        if ($tempArray['Key'] == $arrayOfData['Key']) {
            foreach ($totalsToBeAdded as $key) {
                $arrayOfData[$key] += $tempArray[$key];
            }
        }
        unset($tempArray);
    }
}

ここで確認できる唯一の永続的な配列は$totalsToBeAddedand$arrayOfDataです。これは、演算子から 1 次元に見えるため+=、マイクロ最適化以外にできることはあまりありません。

于 2012-11-02T15:44:06.770 に答える