4

최근에 A에서 B로 파일을 전송하는 컨트롤러를 구현해야했습니다. 각각 1 ~ 2MB 크기의 파일이 약 8000 개 있습니다.Java에서 ThreadPoolExecutor를 사용하여 동적 파일 전송 컨트롤러 구현

  • 하나의 파일 전송이 성공하면 다른 스레드를 만듭니다. (현재 corePooleSize +1 증가)
  • 하나의 파일 전송이 실패하면 하나의 스레드 재 시도 전송을 닫습니다 (현재 corePooleSize -1 증가).
  • 하나의 파일 전송이 실패하면 특정 시간 동안 다른 스레드를 생성하지 마십시오.

이 문제는 호스트의 제한을 모르고 최대의 연결 수/최적의 전송 속도를 얻는 것입니다.

이제 내 질문은 ThreadPoolExecutor가이 동작을 구현하는 가장 좋은 방법인가 아니면 더 좋은 방법인가?

//Code simplified 
//add all files to callables with type Future<Boolean> 
while (true) { 

    // entry = get the first result that's done. 

    if (entry.getValue().get() == Boolean.TRUE) { 
     results.remove(entry.getKey()); 
     if (results.size() > threadPool.getCorePoolSize()) { 

      if (System.currentTimeMillis() >= nextAttempt) 
       resizeThreadPool(+1); 
     } 
    } else { 
     resizeThreadPool(-1); 
     nextAttempt = System.currentTimeMillis() + someTimeinMs; 
     entry.setValue(threadPool.submit(entry.getKey())); 
    } 
    if (results.isEmpty()) 
     return true; 
} 

편집 : 매개 변수로 주어진 스레드의 최소 & 최대 수 있습니다.

+0

완전히 다시 생각해 봐야합니다. '최상의 전송 속도'와 관련이있는 계산에 대해서는 아무 것도 없으므로 엄청난 수의 스레드를 생성하게됩니다. CPU와 네트워크에 대해 서로 경쟁하고 절대적으로 아무 곳에도 도달하지 못하게됩니다. 사용해야하는 최대 스레드 수는 경로 대역폭을 대상 전송 속도로 나눈 값입니다. 이 번호는 다소 작음을 알 수 있습니다. – EJP

답변

1

파일 전송 당 가변 성능 (읽기/쓰기가 로컬 디스크 또는 일부 원격 위치에서 발생할 수 있으며 모든 디스크/네트워크 위치에서 사용할 수있는 유효 대역폭이 모두 동일하지 않다는 점에서 매우 흥미로운 문제입니다. 타임스). 그러나 전송 성공/실패를 사용하면 스레드 수를 늘리거나 줄여야 할 때를 결정할 때 좋은 척도가 될지 잘 모르겠습니다. 필자는 쓰레드로 읽기/쓰기 위치를 지나치게 프로비저닝하면 실패가 발생하지 않을 것이라고 생각한다. 아마도 한 번에 하나의 파일을 복사하는 것과 비교할 때 약간의 추가 오버 헤드가 발생할 것이다. 이 경우, 메모리가 부족하거나 복사 할 파일이 부족할 때까지 더 많은 스레드를 생성 할 수 있습니다.

다른 말로 문제를 해결하는 것이 나을 것이라고 생각합니다. 다음의 제약 내 마음에 가장 중요한 위치 :

  1. 당신은 어딘가에에서 각 파일 을 읽어야합니다.
  2. ~ 각 파일을 작성해야합니다.
  3. 읽기/쓰기 위치는 임의적입니다.
  4. 쓰기 전에 모든 파일을 RAM에 저장할 수는 없습니다.
  5. 무한 수의 스레드를 생성 할 수 없습니다 (시도 할 경우 메모리가 부족합니다).

이러한 제약 조건을 염두에두고 필자는 읽기/쓰기 요청 대기열을 폴링하는 각 풀과 함께 두 개의 스레드 풀 (읽기 용과 쓰기 용)을 유지 관리합니다. 최적의 경우 새 스레드는 발견 된 새로운 읽기/쓰기 위치마다 생성되지만 시스템 메모리 한계 (또는 미리 결정된 수용 가능한 양)를 초과하지 않도록 특정 크기로 제한됩니다. 또한 파일 크기가 버퍼 크기보다 큰 경우 첫 번째 N 바이트를 읽은 다음 다음 N 바이트를 읽기 전에 해당 바이트를 쓰기 큐에 전달하는 버퍼 크기를 설정해야합니다. 이렇게하면 전체 파일을 읽기 전에 큰 파일을 대상에 쓰기 시작할 수 있으므로 쓰기 전에 전체 파일을 읽는 데 필요한 시간과 메모리를 절약 할 수 있습니다. 마지막으로, 쓰기 대기열 크기를 제한하여 프로그램이 주어진 시간에 프로그램의 RAM 할당에 맞출 수있는 것보다 많은 데이터를 읽지 못하게 할 수 있습니다.

+0

답변 해 주셔서 감사 드리며 저의 솔루션에도 만족하지 않았습니다. 나는 매개 변수에 하나의 최소 및 최대 풀 크기를 지정해야한다는 것을 잊어 버렸다. 귀하의 포인트 1. & 2 : 모든 읽기 및 쓰기 작업이 이미 구현되었습니다. 나는 그것들을 수정할 수없고 callable로서 완전한 전송 방법을 얻는다. 내가 읽거나 쓰는 모든 위치는 원격입니다 (예 : Google Cloud Storage, S3 ... 그러나 사용중인 FTP 및 FTP 서버도 30 이상의 모든 연결을 거부합니다. 25 개의 스레드로 전송을 시작합니다. 31 시까 지 증가하고 실패하면 30으로 계속됩니다. – Tharon