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초.

장기간 실행되는 Perl 프로세스 중 프로세서 코어를 살펴보면 top점유된 코어의 I/O 대기 비율(%wa)이 70%를 초과하는 것을 볼 수 있습니다. 이는 일종의 디스크 경합이 있음을 의미합니다(모든 파일이 하나의 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);

자바

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의 읽기 기능을 사용하여 한 번에 더 큰 덩어리를 얻는 것입니다. 저것가능한성능을 향상시킵니다.

또 다른 옵션은 다양한 mmap 관련 perl 모듈을 조사하는 것입니다.

답변2

실제로 답변은 아니지만 주석에서 코드 형식이 잘못되었습니다.

GNU Parallel의 경우 해당 버전을 사용하여 복제합니다. 1GB/s/코어를 순차적으로 제공하고 병렬로 잘 실행됩니다.

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

답변3

안녕하세요. 그렇지 않을 수도 있지만 처음 관찰해 보면 귀하의 Perl 스크립트가 순차 해석 모드에서 실행되고 있는 것으로 보입니다. 그리고 Java 프로그램은 컴파일된 프로그램으로 실행되며 병렬로 실행됩니다. 이는 완료 속도의 차이를 설명할 수 있습니다.

관련 정보