在 Ubuntu 上並行運行作業 - Perl 和 Java 之間的 I/O 爭用差異

在 Ubuntu 上並行運行作業 - Perl 和 Java 之間的 I/O 爭用差異

如果這不是主題,我們深表歉意 - 它涉及在 Ubuntu 系統上並行運行 I/O 密集型 Perl/Java 腳本的相對效率。

我編寫了兩個簡單版本的文件複製腳本(Perl 和 Java) - 請參閱下文。當我在 15GB 檔案上運行腳本時,每個腳本在執行 Ubuntu Server 12.04 的 48 核心電腦上花費的時間相似(perl 2 分 10 秒,java 2 分 27 秒)。

但是,當我並行運行 6 個實例(每個實例運行不同的 15GB 輸入檔)時,我觀察到處理時間差異很大:

  • Perl:一個實例在 2 分 6 秒內完成,所有其他實例需要 27 分 26 秒 - 28 分 10 秒。
  • Java:所有實例需要 3 分 27 秒 - 4 分 37 秒。

查看top長時間運行的Perl 進程期間的處理器核心,我發現佔用的核心的I/O 等待百分比(%wa) 超過70%,這意味著存在某種磁碟爭用(所有檔案都在一個HD 上) 。那麼,大概 JavaBufferedReader對這種磁碟爭用就不太敏感。

問題 - 這看起來是一個合理的結論嗎?如果是這樣,有人可以建議我可以在作業系統層級或 Perl 中採取任何操作,以使 Perl 腳本與 Java 一樣有效率地完成此類任務嗎?

注意 - 我的目標不僅僅是複製文件 - 我的真實腳本包含額外的邏輯,而是表現出與下面的簡化腳本相同的效能行為。

珀爾

#!/usr/bin/perl -w
open(IN, $ARGV[0]) || die();
open(OUT, ">$ARGV[1]") || die();
while (<IN>) {
    print OUT $_
}
close(OUT);
close(IN);

爪哇

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。

你可以在這裡嘗試一些事情。一種是使用perl中的read函數一次取得更大的區塊。那可能提高性能。

另一種選擇可能是研究各種與 mmap 相關的 perl 模組。

答案2

不是真正的答案,但程式碼在註解中的格式不正確。

對於 GNU Parallel,我使用它的一個版本來複製。它可以按 1 GB/s/core 的順序交付,並且並行運行良好:

perl -e '$left=-s STDIN;
  while($read=sysread(STDIN,$buf,$left>131072?131072:$left)){
    $left-=$read;
    syswrite(STDOUT,$buf);
  }' < in > out

答案3

您好,情況可能並非如此,但從第一次觀察來看,您的 perl 腳本正在以順序解釋的方式運行。當您的 java 程式作為編譯程式運行並且以並行方式運行時。這可能是完成速度差異的原因。

相關內容