2014-05-12 3 views
1

약 250K 개의 파일이 들어있는 약 500MB 크기의 zip 파일의 내용을 추출하려고합니다.큰 zip 파일의 내용을 추출하십시오.

"pool-1-thread-7" prio=5 tid=7fd8093dd000 nid=0x11d3f3000 waiting for monitor entry [11d3f2000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at de.schlichtherle.truezip.socket.ConcurrentInputShop$SynchronizedConcurrentInputStream.close(ConcurrentInputShop.java:223) 
    - waiting to lock <785460200> (a de.schlichtherle.truezip.fs.archive.FsDefaultArchiveController$Input) 
    at de.schlichtherle.truezip.io.DecoratingInputStream.close(DecoratingInputStream.java:79) 
    at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:178) 
    at ArchiveReaderExecutor$FileExtractorSavor.run(ArchiveReaderExecutor.java:136) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:695) 

    Locked ownable synchronizers: 
    - <79ed370e0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) 
"pool-1-thread-5" prio=5 tid=7fd8093db800 nid=0x11d1ed000 waiting for monitor entry [11d1ec000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at de.schlichtherle.truezip.socket.ConcurrentInputShop$SynchronizedConcurrentInputStream.close(ConcurrentInputShop.java:223) 
    - waiting to lock <785460200> (a de.schlichtherle.truezip.fs.archive.FsDefaultArchiveController$Input) 
    at de.schlichtherle.truezip.io.DecoratingInputStream.close(DecoratingInputStream.java:79) 
    at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:178) 
    at ArchiveReaderExecutor$FileExtractorSavor.run(ArchiveReaderExecutor.java:136) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:695) 

    Locked ownable synchronizers: 
    - <79ed46468> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) 
: - 여기

내가 할 노력하고 무엇 나는 동시에이 코드를 실행하고 때,

import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

import org.apache.commons.io.FileUtils; 
import org.apache.commons.io.IOUtils; 

import de.schlichtherle.truezip.file.TFile; 
import de.schlichtherle.truezip.file.TFileInputStream; 

public class ArchiveReaderExecutor { 

    private final ExecutorService pool; 

    public ArchiveReaderExecutor() { 
     pool = Executors.newFixedThreadPool(8); 
    } 

    /** 
    * Splits the archive file into list of lists as provided in the batch size 
    * variable 
    * 
    * @param archive 
    * 
    * @return 
    */ 
    public List<List<TFile>> splitArchiveFile(final File archive) { 
     final TFile tFile = new TFile(archive.getAbsolutePath()); 
     final ArrayList<TFile> individualFiles = new ArrayList<TFile>(); 
     recursivelyReadLeafnodes(tFile, individualFiles); 
     final List<List<TFile>> returnList = new ArrayList<List<TFile>>(); 

     /* 
     * Splitting the entire list into list of objects for batch processing 
     */ 
     int count = 0; 
     List<TFile> innerList = null; 

     for (TFile splitFile : individualFiles) { 
      if (count == 0) { 
       innerList = new ArrayList<TFile>(); 
       returnList.add(innerList); 
      } 

      if (count < 100) { 
       ++count; 
      } else { 
       count = 0; 
      } 
      innerList.add(splitFile); 
     } 
     return returnList; 
    } 

    public List<TFile> recursivelyReadLeafnodes(TFile inputTFile, 
      ArrayList<TFile> individualFiles) { 
     TFile[] tfiles = null; 

     if (inputTFile.isArchive() || inputTFile.isDirectory()) { 
      tfiles = inputTFile.listFiles(); 
     } else { 
      tfiles = new TFile[0]; 
      tfiles[0] = inputTFile; 
     } 

     for (final TFile tFile : tfiles) { 
      if (tFile.isFile() && !tFile.getName().startsWith(".")) { 
       individualFiles.add(tFile); 
      } else if (tFile.isDirectory()) { 
       recursivelyReadLeafnodes(tFile, individualFiles); 
      } 
     } 

     return individualFiles; 
    } 

    public void runExtraction() { 

     File src = new File("Really_Big_File.zip"); 
     List<List<TFile>> files = splitArchiveFile(src); 
     for (List<TFile> list : files) { 
      pool.execute(new FileExtractorSavor(list)); 
     } 
     pool.shutdown(); 

    } 


    class FileExtractorSavor implements Runnable{ 
     List<TFile> files; 
     public FileExtractorSavor(List<TFile> files) { 
      this.files = files; 
     } 
     @Override 
     public void run() { 
      File file = null; 
      TFileInputStream in = null; 
      for (TFile tFile : files) { 
       try { 
        in = new TFileInputStream(tFile); 
        file = new File("Target_Location"+tFile.getName()); 
        FileUtils.writeStringToFile(file, IOUtils.toString(in)); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } finally { 
        IOUtils.closeQuietly(in); 
       } 
      } 

     } 

    } 

    public static void main(String[] args) { 
     new ArchiveReaderExecutor().runExtraction(); 
    } 
} 

를 대기/차단 된 상태에서 스레드의 많은이 있습니다, 여기에 스레드 덤프입니다 이 단일 스레드에서 실행되면서

TFile.cp_r(src, dst, TArchiveDetector.NULL, TArchiveDetector.NULL); 

그것은 훨씬 더 오래 걸렸다 :

또한 사용했습니다.

내 질문에 트루 젝을 사용하여 자바에서 zip 파일의 내용을 추출하는 가장 빠르고, 최적의 방법은 무엇입니까?

+0

차단 된 스레드가 좋지 않다고 생각하는 이유는 무엇입니까? – chrylis

+0

거의 모든 스레드가 수명의 40 % 이상 차단 상태에 있습니다. 이상하지 않습니까? 또한 인플레이션 프로세스는 주어진 유스 케이스와 25K 레코드가 포함 된 50MB 크기의 파일에 대해 약 1 시간이 걸리며 프로세스가 3 분 내에 완료됩니다. 수학에 따르면, 10 배의 파일을 포함하는 더 큰 파일이 30 분 안에 완료되지 않아야합니까? – Shyam

+1

자세한 정보가 없으면 특정 성능 문제에 관해 말할 수 없지만 I/O 집약적 인 응용 프로그램의 스레드가 많이 차단되는 것은 놀라운 일이 아닙니다. – chrylis

답변

1

여기에 문제가 없습니다. TrueZIP/TrueVFS는 탑재 된 보관 파일마다 단일 파일 설명자를 유지 관리합니다. 여러 스레드가 아카이브 파일의 내용을 동시에 읽을 때 TrueZIP/TrueVFS 커널은 모든 액세스를 직렬화하여 하나의 스레드 만 파일 설명자를 사용하고 언제든지 위치를 업데이트합니다. 한편 다른 모든 스레드는 차단됩니다.

+0

이 중요한 요지를 가져 주셔서 감사합니다. 나는 독자가 단일 쓰레드와 다중 쓰레드를 만드는 것을 끝내었다. 그런 식으로 경쟁 쓰레드가 읽기 작업을 차단하지 않을 것이다. 이제 전체 인플레이션 프로세스는 2-3 분 내에 완료되어 ~ 500MB 크기의 파일이됩니다. – Shyam

+0

독자가 단일 스레드라고 말하면 recursivelyReadLeafnodes 함수를 의미합니까? 실행할 수 없다면? – vivek85

+0

아니요, 구현을 수정했습니다. FileExtractorSavor에서 추출을 처리하는 대신 개별 아카이브 파일의 데이터를 먼저 문자열로 읽은 다음이 문자열을 병렬로 처리했습니다. – Shyam

관련 문제