これがトピックから外れている場合はお詫びします-UbuntuシステムでI/Oを多用するPerl/Javaスクリプトを並行して実行することの相対的な効率に関係します。
私はファイルコピースクリプトの2つの単純なバージョン(PerlとJava)を作成しました-以下を参照してください。 15GBのファイルでスクリプトを実行すると、Ubuntu Server 12.04(Perl 2m10s、Java 2m27s)を実行している48コアのマシンでそれぞれ同じ時間がかかります。
ただし、6つのインスタンスを並行して実行し、それぞれが異なる15GBの入力ファイルで動作している場合、処理時間は大きく異なります。
長時間実行されているPerlプロセス中のtop
のプロセッサコアを見ると、占有されているコアのI/O待機率(%wa)が70%以上であり、何らかのディスク競合(すべてのファイル)が発生していることがわかります。 1つのHDにあります)。おそらく、JavaのBufferedReader
は、このディスクの競合に対する感度がどういうわけか低くなっています。
質問-これは合理的な結論のように思われますか?もしそうなら、この種のタスクでPerlスクリプトをJava)と同じくらい効率的にするために、OSレベルまたはPerlで実行できるアクションを誰かが提案できますか?
注-私の目標は単にファイルをコピーすることではありません-私の実際のスクリプトには追加のロジックが含まれていますが、以下の簡略化されたスクリプトと同じパフォーマンス動作を示します。
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();
}
}
}
パフォーマンスの違いは、PerlとJavaの間でバッファリングがどのように機能するかにある可能性が最も高いです。この場合、JavaでAbufferedReaderを使用したので、利点があります。Perlはディスクから約4kのバッファーを実行します。
ここでいくつか試してみることができます。 1つは、Perlの読み取り関数を使用して、一度に大きなブロックを取得することです。それmayパフォーマンスを向上させます。
別のオプションは、さまざまなmmap関連のPerlモジュールを調査することかもしれません。
実際には答えではありませんが、コードはコメントでうまくフォーマットされません。
GNU Parallelの場合、これのバージョンを使用してコピーします。1GB/ s/coreの順序で配信でき、並列で正常に機能します。
Perl -e '$left=-s STDIN;
while($read=sysread(STDIN,$buf,$left>131072?131072:$left)){
$left-=$read;
syswrite(STDOUT,$buf);
}' < in > out