2015-01-30 1 views
3

VM에 많은 파일을 작성해야합니다. 300.000 개 정도의 파일을 작성해야하지만, 오늘은 파일 생성을위한 작업을 잘 수행하지만 작업을 완료하는 데는 3 ~ 4 시간이 걸립니다.mutiples 스레드를 사용하여 파일 쓰기

이 병렬 스레드를 구현하는 방법을 모르겠습니다. 누군가 나를 도와주는 모범을 보입니다.

감사

+0

일부 코드를 게시해야합니다. 대부분의 파일 입출력은'BufferedOutputStream.'을 사용하여 엄청나게 빨라질 수 있습니다. – EJP

답변

6

나는 당신이 멀티 스레딩에서하지만 코드의 변경의 최소 혜택을받을 수있는 방법을 일했다. SSD의에

import java.io.*; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 

/** 
* Created by peter.lawrey on 30/01/15. 
*/ 
public class ConcurrentFileWriter { 
    private final ThreadPoolExecutor es; 
    private final int maxQueueSize; 

    public ConcurrentFileWriter() { 
     this(4, 10000); 
    } 

    public ConcurrentFileWriter(int concurrency, int maxQueueSize) { 
     this.maxQueueSize = maxQueueSize; 
     es = (ThreadPoolExecutor) Executors.newFixedThreadPool(concurrency); 
    } 

    public OutputStream newFileOutputStream(final String filename) { 
     return new ByteArrayOutputStream() { 
      @Override 
      public void close() throws IOException { 
       super.close(); 
       final ByteArrayOutputStream baos = this; 
       if (es.getQueue().size() > maxQueueSize) 
        try { 
         Thread.sleep(10); 
        } catch (InterruptedException e) { 
         throw new AssertionError(e); 
        } 
       es.submit(new Runnable() { 
        public void run() { 
         try { 
          FileOutputStream fos = new FileOutputStream(filename); 
          fos.write(baos.toByteArray()); 
          fos.close(); 
         } catch (IOException ioe) { 
          System.err.println("Unable to write to " + filename); 
          ioe.printStackTrace(); 
         } 
        } 
       }); 
      } 
     }; 
    } 

    public PrintWriter newPrintWriter(String filename) { 
     try { 
      return new PrintWriter(new OutputStreamWriter(newFileOutputStream(filename), "UTF-8")); 
     } catch (UnsupportedEncodingException e) { 
      throw new AssertionError(e); 
     } 
    } 

    public void close() { 
     es.shutdown(); 
     try { 
      es.awaitTermination(2, TimeUnit.HOURS); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
      Thread.currentThread().interrupt(); 
     } 
    } 

    public static void main(String... args) { 
     long start = System.nanoTime(); 
     ConcurrentFileWriter cfw = new ConcurrentFileWriter(); 
     int files = 10000; 
     for (int i = 0; i < files; i++) { 
      PrintWriter pw = cfw.newPrintWriter("file-" + i); 
      pw.println("Hello World"); 
      pw.close(); 
     } 
     long mid = System.nanoTime(); 
     System.out.println("Waiting for files to be written"); 
     cfw.close(); 
     long end = System.nanoTime(); 
     System.out.printf("Took %.3f seconds to generate %,d files and %.3f seconds to write them to disk%n", 
       (mid - start)/1e9, files, (end - mid)/1e9); 
    } 
} 

이 무엇이하는 일은 당신이 지금, 당신은 단일 스레드 코드를 작성할 수 그러나 디스크에 실제 기록은 다시 지상 과제로 수행된다

Waiting for files to be written 
Took 0.075 seconds to generate 10,000 files and 0.058 seconds to write them to disk 

를 인쇄합니다.

참고 : 파일을 실제로 디스크에 쓸 때까지 기다리지 않으려면 close()를 호출해야합니다.


엄청난 수의 파일을 쓰는 데있어서의 문제는 많은 HDD 작업입니다. 다중 쓰레드를 사용해도 드라이브가 더 이상 쓰러지지는 않습니다. 파일을 열거 나 닫을 때마다 약 2 IO (IO 작업)를 사용합니다. HDD가 있고 80 IOPS (IOs per Second)를 지원하면 초당 40 개의 파일을 열거 나 닫을 수 있습니다. 즉 300,000 개의 파일에 대해 약 2 시간.

비교해 보면 SSD를 사용하면 1000 배 빨라진 80,000 IOPS를 얻을 수 있으며 파일을 열고 닫을 때만 8 초를 소비 할 수 있습니다.

일단 SSD로 전환하면 다중 스레드를 사용하는 것이 좋습니다. 이 작업을 수행하는 간단한 방법은 당신이에 처리 할 수있는 파일을 공급 하나 개의 스레드를 가지고 사용하기 위해 필요한이

IntStream.range(0, 300000).parallel(). 
     .forEach(i -> createFile(i)); 
+0

디스크의 I/O 작업에 대한 설명을 감사하지만 자바 6을 사용합니다.이 솔루션은 내 문제를 해결하지 못합니다. 현재 나는 나쁜 해결책 인 재귀 연산을 사용한다. ThreadPool에 대해 여러 가지 threds를 병렬로 실행하도록 설정했는데 예제가 명확하지 않습니다. – danillonc

+0

@danillonc Java 7이 End of Public 업데이트가되기를 감안할 때 Java 8로 업그레이드하는 것이 좋습니다. Java 6에서이를 수행하는 방법을 배우는 것이 어려울 것입니다. (멀티 스레딩은 HDD에 도움이되지는 않을 것입니다.) –

+0

I 내 프로젝트가 아니기 때문에 내 Java 버전을 업그레이드 할 수 없습니다. 이 프로젝트는 기업의 프로젝트입니다. – danillonc

0

같은 것을

할 수있는 8 자바 스트림 API를 사용하는 것입니다 대기열 및 대기열에서 대기 행렬을 풀고 파일을 쓰는 스레드 풀. 이를 수행하는 한 가지 방법은 간단한 제작자 소비자를 사용하는 것입니다.

다음은 예입니다. Multithreaded producer consumer in java

+0

@ Rajasekar 감사. 나는이 예제를 보게 될 것이고, 그것은 매우 단순 해 보인다. – danillonc

관련 문제