0

나는 데이터베이스를 쿼리하고 수십만 개의 레코드를 검색 중입니다. 그런 다음 반환 된 SqlReader를 읽고 레코드 당 새 작업을 만듭니다. 그런 다음 새 작업은 장기간에 걸친 작업을 수행합니다.대형 while 루프의 반복마다 작업을 만드는 데 성능 및/또는 안전 문제가 있습니까?

내 코드는 다음과 다소 같습니다

void ProcessRecords(SqlDataReader reader) 
    { 
     if (!reader.HasRows) 
     { 
      return; 
     } 
     using (reader) 
     { 
      while (reader.Read()) 
      { 
       var filePath = BuildFilePath(reader); 
       var imageId = (int)reader["PhotoID"]; 
       Task.Run(() => { ProcessRecord(imageId, filePath); }) 
        .ContinueWith((task) => { Progress.Report("Processing " + Path.GetFileName(filePath)); }); 
      } 
     } 
    } 

내가 작업에 의해 사용되는 스레드의 수를 제한하는 세마포어를 사용하는 수석 개발자가 조언했다. 이것이 올바른 접근 방법인가요? 문제는 항상

+0

표시된 코드를 사용하면 모든 레코드 처리가 완료되기 전에 'ProcessRecords'가 반환 될 수 있습니다. 그게 기대 되니? – svick

+0

예, 예상됩니다. – ravp

답변

1

,

얼마나 많은 오버 헤드 병렬 처리가 병렬로 수행 단위 작업에 필요합니까?

이는 병렬 처리를 관리하는 오버 헤드와 수행되는 작업량에 따라 다릅니다.

일반적으로 저렴한 병렬 처리에는 병렬 작업 단위를 포크하는 데 수십에서 수백 개의 명령어가 필요합니다. 즉, 수행해야 할 작업은 수행중인 실제 작업이 병렬 처리 오버 헤드를 지배 할 수 있도록 수천 개의 지침이어야합니다.

쓰레딩 생성이 저렴하지 않기 때문에 "병렬 처리"비용이 많이 발생합니다 (예 : "쓰레드 생성"). 대부분의 계산은 이렇게 포크를 정당화 할만큼 비싸지 않습니다.

OP의 예가 의미가있을 수있는 아주 드문 경우입니다. 헤드를 움직여야하는 경우 수십 밀리 초가 소요되는 디스크에 대한 트랜잭션을 수행합니다.

일반적으로 디스크 드라이브에 대해 병렬 I/O를 수행하면 작동하지 않습니다. 그것은 단지 하나의 헤드를 가지며, 따라서 디스크에 대한 병렬 연산은 직렬화되고 중첩되지 않는다.

"ProcessRecord"시간이 디스크 시간보다 우세하면이 코드가 효과적 일 수 있습니다. (확실히, OP는 프로그램이 얼마나 효과적인지 측정했습니다.). 이 경우 라이브 스레드의 수를 CPU 수의 배수로 제한하면 수십만 개의 스레드를 추적하는 기가 바이트의 메모리를 사용하지 않고도 한계를 넘지 않는만큼 병렬 처리를 수행 할 수 있습니다 (OS에서 수행하는 경우에도 마찬가지). 그것은 긴 파일 목록이 제공 할 수도 있습니다.