2013-07-25 6 views
1

이 글에 실을 새 것으로 여기고 있습니다. 멀티 스레딩을 사용하는 응용 프로그램이 있습니다. 나는 ftp 서버에 심상의 수천을 올려주기하는 기능이있다. 각 이미지마다 새 스레드를 만듭니다. 이 스레드는 ftp 서버에 연결하는 함수를 호출하고 파일을 업로드하고 성공적으로 업로드되면 부울 값을 반환합니다.C에서 멀티 스레드를 사용하는 동안 예외가 발생했습니다.

내 문제는 내가 수천 개의 이미지를 업로드하고 각각 자체 스레드를 만들고 있기 때문에 언젠가 메모리 부족 예외와 응용 프로그램이 멈추는 경우입니다.

내 코드는 다음과 같습니다

public Int16 UploadFiles(string[] files) 
{ 
    foreach (var fileName in files) 
     { 
      if (UploadFile(fileName)) 
      { 
       strLogText += "\r\n\tFile: " + fileName + " downloaded."; 
      } 
     } 
} 

private bool UploadFile(string fileName) 
    { 
     var blnDownload = false; 
     var thread = new Thread(() => DownLoadFileNow(fileName, out blnDownload)) {IsBackground = true}; 
     thread.Start(); 
     return blnDownload; 
    } 

    private void DownLoadFileNow(string fileName, out bool blnDownload) 
    { 
     //Get file path and name on source ftp server 
     var srcFolder = GetSrcFolderName(fileName); 

     //Get Local Folder Name for downloaded files 
     var trgFolder = GetLocalFolder(fileName, "D"); 

     var reqFtp = 
      (FtpWebRequest) WebRequest.Create(new Uri("ftp://" + _strSourceFtpurl + srcFolder + "/" + fileName)); 
     reqFtp.Method = WebRequestMethods.Ftp.DownloadFile; 
     reqFtp.UseBinary = true; 
     reqFtp.Credentials = new NetworkCredential(_strSourceFtpUser, _strSourceFtpPassword); 
     var outputStream = new FileStream(trgFolder + "\\" + fileName, FileMode.Create); 

     try 
     { 
      var response = (FtpWebResponse) reqFtp.GetResponse(); 
      var ftpStream = response.GetResponseStream(); 
      const int bufferSize = 2048; 
      var buffer = new byte[bufferSize]; 

      if (ftpStream != null) 
      { 
       int readCount = ftpStream.Read(buffer, 0, bufferSize); 
       while (readCount > 0) 
       { 
        outputStream.Write(buffer, 0, readCount); 
        readCount = ftpStream.Read(buffer, 0, bufferSize); 
       } 

       ftpStream.Close(); 
      } 
      response.Close(); 
      blnDownload = true; 
     } 
     catch (WebException ex) 
     { 
      _log.WriteLog("Error in Downloading File (" + fileName + "):\r\n\t" + ex.Message, ""); 
      //Delete newly created file from local system 
      outputStream.Close(); 
      if (File.Exists(trgFolder + "/" + fileName)) 
       File.Delete(trgFolder + "/" + fileName); 
     } 
     catch (Exception ex) 
     { 
      _log.WriteLog("Error in Downloading File (" + fileName + "):\r\n\t" + ex.Message, ""); 
     } 
     finally 
     { 
      outputStream.Close(); 
      outputStream.Dispose(); 
     } 
     blnDownload = false; 
    } 

도움이 나를 한 번에 실행하지 않는 이상 10-20 이상의 스레드가되도록 내가 스레드의 수가 생성되는 제한 할 수있는 방법을 알려 주시기 바랍니다.

+1

[스레드가 1MB의 메모리를 사용합니다] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85)asp)); 그래서 당신은 오류가 발생합니다. 아래 답변에서 제안 된 것처럼 대신 TPL을 사용해야합니다. – GolfWolf

+0

한 번에 다운로드 할 수있는 항목 수를 제한하는 대기열을 만드십시오. 어쩌면 스레드 대신 Tasks를 사용하여 작업이 끝났음을 알 수 있습니다. – Robert

+0

스레드가 8 개 이상 (logical_processors) 사용하는 Windows 프로세스는 수행 또는 크기 조정이 실패합니다. 예를 들어, 요청을 처리하기 위해 8 개 이상의 스레드를 사용하는 서비스 응용 프로그램이있는 단일 CPU 시스템 (예 : 소켓 수락)은 상자를 신속하게 무릎으로 가져갑니다. –

답변

2

UploadFiles (string 파일) 메서드에서 대신 DownloadFileNow를 호출하는 Parallel.ForEach()를 사용하여 UploadFiles (string [] 파일)의 foreach를 바꾸어보십시오.

Parallel.Foreach는 원하는대로 스레드 풀에서 스레드를 가져오고 코드를 단순화합니다.

Parallel.ForEach(files, fileName => 
     DownloadFileNow(fileName); 
     strLogText += "\r\n\tFile: " + fileName + " downloaded."; 
); 
+0

고마워, 이제 "AggregateException 처리되지 않았습니다"지고있다. 어떤 생각이 어떻게 해결할 수 있습니까? – sarojanand

+0

나는 strLogText를 비동기식으로 업데이트하는 것과 관련이 있다고 생각한다. strLogText로 무엇을합니까? – user467384

+0

함수 끝에 얼마나 많은 파일과 파일이 업로드되었는지를 알기 위해 로그 파일을 추가합니다. 각 시간을 추가하는 대신 문자열에 추가하고 각 루프가 끝난 후에 로그 파일에 추가합니다. – sarojanand

3

이 많은 스레드를 만들 수 없습니다. 한 가지 대안은 파렐 확장을 사용하는 것입니다. 다른 사람들이 지적했듯이

public void UploadFiles(string[] files) 
{ 
    files.AsParallel().ForAll(fileName => 
    { 
     if (UploadFile(fileName)) 
     { 
      strLogText += "\r\n\tFile: " + fileName + " downloaded."; 
     } 
    }); 
} 
1

, 당신은 많은 스레드 것을 생성 할 수 없습니다. 이제 ... Parallel.ForEach()은 멋진 구문 설탕을 줄 것이며 그 경로를 따라 가야합니다!

스레드 풀을 개념으로 검색해야한다는 점을 지적하고 싶습니다. 여러 스레드가 병렬로 실행되는 것은 의미가 없습니다. 이러한 각각의 작업에는 최적의 스레드 수가 있으며, 그 이상의 스레드 오버 헤드가 실제로 느려지 기 시작합니다. 또는 귀하의 경우 모든 기억을 다 사용하십시오.

책상 (폴더)에 앉아있는 사진 더미와 당신을 위해 일하는 직원으로서의 작업을 생각하면 한 명의 직원이 책상에서 사진을 가져 와서 봉투에 넣고 각 사진을 우체국으로 가져와 영원히 가져갈 것입니다. 그래서 당신은 다른 직원을 고용합니다. 그리고 또 다른. 그러나 일단 일정량의 사진 스탬프를 찍으면 다른 사람들과 득실 거리기 시작합니다. 그들은 책상 앞에 대기하고 있습니다. 그들은 우체국 앞에서 줄을 서고 있습니다. 그리고 전체 봉투 상황은 사무 용품을 담당하는 가난한 마리아에게 고통 스러울뿐입니다. 그들은 또한 그녀 앞에서 기다리고 있습니다! 그래서, 최적의 직원 수를 알아 내고 (테스트를 실행하거나 조금만 짐작할 수 있습니다.) 책상이 비워 질 때까지 작업을 반복하도록 할당하십시오.

이것은 상당히 위로 나타나는 마스터/슬레이브 패턴입니다. 자주.

관련 문제