在Ubuntu上并行运行作业 – Perl和Java之间的I / O争用差异

如果这不是主题,请道歉 – 它涉及在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模块.

上一篇:data parallelism


下一篇:Concurrency in C# Cookbook中文翻译 :1.2并发性概述:并行程序设计导论