2

入力ファイルはユーザーが構成し、そのサイズは制限されていませんが、サーバーのメモリを占有することなく、テキスト ファイルの文字エンコーディングを変換する必要があります。

exec() を使用してunixのiconvコマンドをラップする方が効率的でしょうか(アプリケーションで他のファイル操作のためにすでに使用していますが、これは避けたいと思います)、またはファイルを1行ずつ読み取って出力する必要があります別のファイル?

私はこのように働くことを考えています:

$in = fopen("in.txt", "r");
$out = fopen("out.txt", "w+");
while(($line = fgets($in, 4096)) !== false) {
    $converted = iconv($charset["in"], $charset["out"], $line);
    fwrite($out, $converted);
}
rename("out.txt", "in.txt");

ファイルを高速かつ効率的に変換するためのより良い方法はありますか? これはかなりCPUを集中的に使用する可能性があると考えていますが、iconv自体は高価なタスクであると考えているため、実際にサーバーをまったく消費しないようにすることができるかどうかはわかりません.

ありがとう!

4

4 に答える 4

2

入力していただきありがとうございます。それに基づいて「宿題」を行い、実際の CSV データの 50MB サンプルを使用して結果を取得しました。

まず、PHP を使用してファイルを反復処理します。

$in = fopen("a.txt", "r");
$out = fopen("p.txt", "w+");

$start = microtime(true);

while(($line = fgets($in)) !== false) {
    $converted = iconv("UTF-8", "EUC-JP//TRANSLIT", $line);
    fwrite($out, $converted);
}

$elapsed = microtime(true) - $start;
echo "<br>Iconv took $elapsed seconds\r\n";


Iconv には 2.2817220687866 秒かかりました

それはそれほど悪くないと思うので、#bashでまったく同じアプローチを試したので、すべてのファイルをロードする必要はありませんが、代わりに各行を反復処理します(Lajos Veresの回答を理解しているため、正確には発生しない可能性があります)。実際、この方法は正確には効率的ではありませんでした (CPU は常に大きな負荷にさらされていました)。また、出力ファイルは他の 2 つよりも小さいですが、簡単に見てみると同じように見えます。したがって、bash スクリプトで間違いを犯したに違いありませんが、とにかくパフォーマンスにそのような影響を与えるべきではありません。

#!/bin/bash
echo "" > b.txt
time echo $(
    while read line
    do
        echo $line |iconv -f utf-8 -t EUC-JP//TRANSLIT >> b.txt
    done < a.txt
)

実 9m40.535s ユーザー 2m2.191s sys 3m18.993s

そして、私がメモリを独占すると予想していた古典的なアプローチですが、CPU /メモリの使用量をチェックすると、他のどのアプローチよりも多くのメモリを必要としないように見えたため、勝者になりました:

#!/bin/bash
time echo $(
    iconv -f utf-8 -t EUC-JP//TRANSLIT a.txt -o b2.txt
)

実際の 0m0.256s ユーザー 0m0.195s システム 0m0.060s

より大きなファイル サンプルを取得して、2 つのより効率的な方法をテストし、メモリ使用量が大幅に増加しないことを確認しますが、結果は、bash でファイル全体を 1 回通過するのが最も効果的であると想定するのに十分明らかです。効率的です(PHPでファイル全体を配列/文字列にロードすることは決して良い考えではないと思うので、PHPではそれを試しませんでした)。

于 2013-09-29T08:37:46.663 に答える
1

参考までに: http://sourceware.org/bugzilla/show_bug.cgi?id=6050

とにかく、OS は遅かれ早かれファイル全体を読み取る必要があります。これは、キャッシュのパージを読み取るときに、lru のようなロジックがメモリを解放することを意味します。lru は、おそらく古いページが破棄されることを意味します。

システムがこれをどのように許容するかを 100% 確信することはできません。このプロセスを別のハードウェアまたは仮想化で分離する必要がありますが、これらのソリューションもボトルネックになる可能性があります。

健全性テストは、おそらく最も費用対効果の高い方法です。しかし、予想されるワークロードではなく、実装がほとんどの頭痛の種となるわけではありません。

つまり、100 の並列スレッドで大量の g ファイルを処理することは、1 日に数ファイルを処理することとはまったく異なります。

于 2013-09-28T23:20:32.183 に答える