如果这不是主题,请道歉 – 它涉及在Ubuntu系统上并行运行I / O重的Perl / Java脚本的相对效率.
我编写了两个简单版本的文件复制脚本(Perl和Java) – 见下文.当我在15GB文件上运行脚本时,每个运行Ubuntu Server 12.04(perl 2m10s,java 2m27s)的48核机器上的时间相似.
但是,当我并行运行六个实例,每个实例在不同的15GB输入文件上运行时,我观察到非常不同的处理时间:
> Perl:一个实例在2m6s完成,所有其他实例需要27m26s –
28m10s.
> Java:所有实例都需要3m27s – 4m37s.
在长期运行的Perl进程中查看顶部的处理器核心,我看到占用的核心的I / O等待百分比(%wa)为70%,这意味着某种磁盘争用(所有文件都在一个HD上).据推测,Java的BufferedReader在某种程度上对此磁盘争用不太敏感.
问题 – 这看起来是一个合理的结论吗?如果是这样,任何人都可以建议我可以在操作系统级别或Perl中执行任何操作,以使Perl脚本像Java一样高效执行此类任务吗?
注意 – 我的目标不仅仅是复制文件 – 我的真实脚本包含其他逻辑,但表现出与下面简化脚本相同的性能行为.
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中使用了一个bufferedReader,这给了它一个优势. Perl确实从磁盘缓冲了大约4k.
你可以在这里尝试一些事情.一种是使用perl中的read函数一次获得更大的块.这可能会提高性能.
另一个选择可能是调查各种mmap相关的perl模块.