話題から外れた内容ならすみません。これは、UbuntuシステムでI / O集約的なPerl / Javaスクリプトを並列に実行することの相対的な効率に関するものです。
私はファイルコピースクリプトの2つの単純なバージョン(PerlとJava)を書いています。以下を参照してください。 15GBファイルでスクリプトを実行したとき、各スクリプトはUbuntu Server 12.04を実行している48コアシステムで同様の時間がかかりました(perl 2分10秒、java 2分27秒)。
ただし、6つのインスタンスを並列に実行すると(それぞれ異なる15GBの入力ファイルを実行する)、処理時間に大きな違いがあります。
- Perl:1つのインスタンスは2分6秒で完了し、他のインスタンスは27分26秒(28分10秒)かかりました。
- Java:すべてのインスタンスに対して3分27秒 - 4分37秒。
長期間実行されているPerlプロセスのうち、プロセッサコアを見ると、占有top
コアのI / O待機率(%wa)が70%を超えることがわかります。これは、一種のディスク競合があることを意味します(すべてのファイルが1つのHDにあります)。 )。おそらく、JavaはBufferedReader
この種のディスク競合にあまり敏感ではないでしょう。
質問 - これは合理的な結論のように見えますか?それでは、そのようなタスクに対してPerlスクリプトをJavaほど効率的にするためにOSレベルやPerlでできることを提案できる人はいますか?
注 - 私の目標は単にファイルをコピーすることではありません。私の実際のスクリプトには追加のロジックが含まれていますが、以下の単純化されたスクリプトと同じパフォーマンス動作を示します。
真珠
#!/usr/bin/perl -w
open(IN, $ARGV[0]) || die();
open(OUT, ">$ARGV[1]") || die();
while (<IN>) {
print OUT $_
}
close(OUT);
close(IN);
Java
import java.io.*;
public class CopyFileLineByLine {
public static void main(String[] args) throws IOException {
BufferedReader br = null;
PrintWriter pw = null;
try {
br = new BufferedReader(new FileReader(new File(args[0])));
pw = new PrintWriter(new File(args[1]));
String line;
while ((line = br.readLine()) != null) {
pw.println(line);
}
}
finally {
if (pw != null) pw.close();
if (br != null) br.close();
}
}
}
ベストアンサー1
パフォーマンスの違いは、PerlとJavaの間のバッファリングの仕組みにあります。この場合、JavaのbufferedReaderを使用して利点を得ました。 Perlはディスクから約4kをバッファリングします。
ここで試すことができるいくつかのタスクがあります。 1つは、Perlの読み取り機能を使用して一度に大きな塊を得ることです。それ可能パフォーマンスを向上させます。
別のオプションは、さまざまなmmap関連のperlモジュールを調べることです。