2014-07-22 4 views
0

나는 돋보이는 편지 병합을 한 다음 PDF로 파일 변환하는 중입니다 ... .Net 4.5를 기반으로하면 스레딩을 할 수있는 몇 가지 방법이 있습니다. thread safe queue를 사용하는 것은 재미있을 것 같지만 (Plan A), 잠재적 인 문제를 볼 수 있습니다. 어떻게 생각해? 나는 그것을 짧게하려고 노력할 것이지만, 필요한 것을 넣을 것입니다.ConcurrentQueue를이 방법이나 개별 스레드로 사용해야합니까?

이 작업은 PDF 변환보다 데이터베이스 처리를 수행하는 데 더 많은 시간이 걸릴 것이라는 가정하에 작동합니다.

두 경우 모두 각 파일에 대한 데이터베이스 처리는 자체 스레드/작업으로 수행되지만 PDF 변환은 많은 단일 스레드/작업 (계획 B)에서 수행되거나 단일 실행 스레드에서 수행 될 수 있습니다 (계획 A). 그것은 제가 궁금해하는 PDF 변환입니다. 그것은 모두 try/catch 문에 있지만 스레드가 실패하거나 모두 실패하지 않아야합니다 (계획 A). 그게 좋은 생각이라고 생각하니? 모든 제안을 부탁드립니다.

/* A class to process a file: */ 
public class c_FileToConvert 
{ 
    public string InFileName { get; set; } 
    public int FileProcessingState { get; set; } 
    public string ErrorMessage { get; set; } 
    public List<string> listData = null; 
    c_FileToConvert(string inFileName) 
    { 
     InFileName = inFileName; 
     FileProcessingState = 0; 
     ErrorMessage = ""; // yah, yah, yah - String.Empty 
     listData = new List<string>(); 
    } 
    public void doDbProcessing() 
    { 
     // get the data from database and put strings in this.listData 
     DAL.getDataForFile(this.InFileName, this.ErrorMessage); // static function 
     if(this.ErrorMessage != "") 
      this.FileProcessingState = -1; //fatal error 
     else // Open file and append strings to it 
     { 
      foreach(string s in this.listData} 
       ... 
      FileProcessingState = 1; // enum DB_WORK_COMPLETE ... 
     } 
    } 
    public void doPDFProcessing() 
    { 
     PDFConverter cPDFConverter = new PDFConverter(); 
     cPDFConverter.convertToPDF(InFileName, InFileName + ".PDF"); 
     FileProcessingState = 2; // enum PDF_WORK_COMPLETE ... 
    }  
} 

/*** These only for Plan A ***/ 
public ConcurrentQueue<c_FileToConvert> ConncurrentQueueFiles = new ConcurrentQueue<c_FileToConvert>(); 
public bool bProcessPDFs; 

public void doProcessing() // This is the main thread of the Windows Service 
{ 
    List<c_FileToConvert> listcFileToConvert = new List<c_FileToConvert>(); 

    /*** Only for Plan A ***/ 
    bProcessPDFs = true; 
    Task task1 = new Task(new Action(startProcessingPDFs)); // Start it and forget it 
    task1.Start(); 

    while(1 == 1) 
    { 
     List<string> listFileNamesToProcess = new List<string>(); 
     DAL.getFileNamesToProcessFromDb(listFileNamesToProcess); 

     foreach(string s in listFileNamesToProcess) 
     { 
      c_FileToConvert cFileToConvert = new c_FileToConvert(s); 
      listcFileToConvert.Add(cFileToConvert); 
     }  

     foreach(c_FileToConvert c in listcFileToConvert) 
      if(c.FileProcessingState == 0) 
       Thread t = new Thread(new ParameterizedThreadStart(c.doDbProcessing)); 

     /** This is Plan A - throw it on single long running PDF processing thread **/ 
     foreach(c_FileToConvert c in listcFileToConvert) 
      if(c.FileProcessingState == 1) 
       ConncurrentQueueFiles.Enqueue(c); 

     /*** This is Plan B - traditional thread for each file conversion ***/    
     foreach(c_FileToConvert c in listcFileToConvert) 
      if(c.FileProcessingState == 1) 
       Thread t = new Thread(new ParameterizedThreadStart(c.doPDFProcessing)); 

     int iCount = 0; 
     for(int iCount = 0; iCount < c_FileToConvert.Count; iCount++;) 
     { 
      if((c.FileProcessingState == -1) || (c.FileProcessingState == 2)) 
      { 
       DAL.updateProcessingState(c.FileProcessingState) 
       listcFileToConvert.RemoveAt(iCount); 
      } 
     } 
     sleep(1000); 
    } 
} 
public void startProcessingPDFs() /*** Only for Plan A ***/ 
{ 
    while (bProcessPDFs == true) 
    { 
     if (ConncurrentQueueFiles.IsEmpty == false) 
     { 
      try 
      { 
      c_FileToConvert cFileToConvert = null; 
      if (ConncurrentQueueFiles.TryDequeue(out cFileToConvert) == true) 
       cFileToConvert.doPDFProcessing(); 
      } 
      catch(Exception e) 
      { 
       cFileToConvert.FileProcessingState = -1; 
       cFileToConvert.ErrorMessage = e.message; 
      } 
     } 
    } 
} 

계획안은 좋은 해결책 인 것처럼 보이지만 작업이 어떻게 든 실패하면 어떻게됩니까? 예, 개별 스레드로 PDF 변환을 수행 할 수 있지만 데이터베이스 처리를 위해 PDF 변환을 예약하려고합니다.

이것은 내가 할 수있는 가장 간단한 코드로 텍스트 편집기에서 작성되었으므로 뭔가있을 수 있지만 생각이 바뀌 었다고 생각합니다.

+0

PDF 변환 CPU 또는 IO가 제한되어 있습니까? – Richard

+0

CPU에 바인딩되어야합니다. 문서 당 약 2 초가 걸립니다. 내 가정은 내 병 목이 데이터베이스에있는 것입니다. – Miguelito

+0

리소스가 성능을 제한하는 위치를 알아야합니다. 모든 CPU 리소스 (코어)를 사용하는 데 효과가있는 동시성 접근 방식은 IO에서 제대로 작동하지 않습니다 (예 : 스레드간에 동일한 총 IO를 분산 시키면 각 변환에 더 오래 걸리고 총 처리량은 거의 변하지 않습니다) . – Richard

답변

0

몇 개의 파일로 작업하고 있습니까? 10? 100,000? 숫자가 매우 큰 경우 각 파일에 대한 DB 쿼리를 실행하기 위해 1 개의 스레드를 사용하는 것은 좋지 않습니다.

스레드는 매우 낮은 수준의 제어 흐름 구조이며, 응용 프로그램 코드에서 많은 지저분하고 자세한 스레드 생성, 결합, 동기화 등을 피하려고 노력하는 것이 좋습니다. 가능한 한 바보 같게 유지하십시오.

방법 : 각 파일에 필요한 데이터를 스레드 안전 큐에 넣으십시오. 결과를 위해 다른 스레드 안전 큐를 만듭니다. 입력 대기열에서 항목을 반복적으로 가져 와서 쿼리를 실행하고 PDF로 변환 한 다음 출력을 출력 대기열로 푸시하는 몇 가지 스레드를 생성합니다. 스레드는 입출력 대기열을 절대적으로 공유해야합니다.

원하는 수의 작업자 스레드를 선택하거나 실험을 통해 좋은 숫자를 실험 할 수 있습니다. 각 파일에 대해 하나의 스레드를 생성하지 마십시오 - 좋은 CPU 및 디스크 활용을 허용하는 번호를 선택하십시오.

또는 언어/라이브러리에 병렬지도 연산자가있는 경우이를 사용하십시오. 주위를 어지럽히는 데 도움이 될 것입니다.

+0

, 그건 내가 당신이 좋아하지만, 만약 내가 반복 것이라고 할 수 – Miguelito

+0

PDF 파일 변환에 대해 하나의 스레드를 사용하고자하는 이유 좋은 생각. 리소스를 효율적으로 사용할 수있는 많은 스레드를 선택하고 큐를 사용하여 스레드간에로드 밸런스를 조정하는 것이 좋습니다. 병렬지도 같은 것을 사용하거나-지도 감소 유틸리티를, 그래서 당신은 전혀 산란 스레드의 세부 사항을 처리 할 필요가 없습니다 수 있다면 더 좋은입니다. –