2016-10-14 4 views
1

테이블에 약 3 백만 행이 있습니다. 모든 행을 가져 와서 해당 행을 처리하는 콘솔 응용 프로그램이 있습니다. 한 번에 1000 개의 행을 가져오고 내 처리 논리를 실행하기 위해 TPL을 사용하고 싶습니다. 다음과 같은 논리를 가질 수 있습니다. ProcessRowsForPage 메서드 내에서 페이지 번호를 기반으로 레코드를 가져옵니다.C#을 사용하여 SQL에서 행 가져 오기

int totalRecordsCount = GetCount(); 
int pagecount = totalRecordsCount/1000; 
for (int j= 0; j <= pagecount; j++) 
{ 
    var pageNo= j; 
    var t = Task.Factory.StartNew(() => 
      { 
       ProcessRowsForPage(pageNo); 
      }); 
    tasks.Add(t); 
} 

이상하게 보일 수도 있지만 총계없이 작업을 생성 할 수있는 방법이 있습니다. do while 루프와 같은 것을 사용하고 페치 할 행이 더 이상 없을 때 작업 생성을 중단합니다.

+0

카운트가없는 경우 작업이 마지막 페이지에 도달했다는 것을 어떻게 알 수 있습니까? 이전 작업을 요청해야하지만 이전 작업이 아직 완료되지 않았을 수 있습니다. – NibblyPig

+0

예 참. 총 수를 알지 못한다면 여러 작업을 만들 수 없다고 생각합니다. – DotNetLearner

+2

잠재적으로 한 번에 ConcurrentQueue 및 Dequeue 1000을 사용할 수 있습니다. – apc

답변

1

잠재적으로 수백만 개의 작업을 생성하는 대신 좋지 않은 아이디어를 생성하는 경우 어떤 종류의 수영장.

배열에서 작업을 3 개 작성하고 모두 시작하십시오.

하나의 작업이 완료되면 더 많은 행이 있으면 다시 설정하십시오.

작업이 더 이상 데이터를 반환하지 않으면 설정을 중지하고 모든 작업이 완료 될 때까지 기다린 다음 작업을 완료하십시오.

예 : Task2가 처음으로 완료되면

TASK1 > GetNext100Rows(0) 
TASK2 > GetNext100Rows(100) 
TASK3 > GetNext100Rows(200) 

이 그것을 다시 시작

TASK1 > GetNext100Rows(0) [Processing] 
TASK2 > GetNext100Rows(300) [Processing] 
TASK3 > GetNext100Rows(200) [Processing] 

보관할가 완료 모든 작업을 다시 시작하고, 각 100 시간을 증가.

마지막으로 작업이 더 이상 데이터를 반환하지 않으면 남아있는 모든 스레드가 완료 될 때까지 기다립니다.

이렇게하려면 플래그 변수 또는 반환 객체를 설정하는 등의 작업으로 데이터가 반환되거나 표시되지 않아야합니다.

2

이러한 상황의 경우 TPL Dataflow을 사용하는 것이 좋습니다.

  • SqlDataReader 또는 BatchSize = 1000
  • 호출 할 것이다 ActionBlock와 데이터베이스에서
  • BatchBlock 데이터를 스트리밍 할 수있는 일이 몇 가지 다른 종류의 : 당신이 다음과 같은 구성 요소가 필요합니다 들어

    ProcessRows 방법

이제 처리 파이프 라인을 생성하려면 블록 함께 : 그 후

batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true }); 

BatchBlockdataReaderPost 행에서 :

while(reader.Read()) 
{ 
    var item = ConvertRow(reader); 
    batchBlock.Post(item); 
} 
// When you get here you've read all the data from the database 
// tell the pipeline that no more data is coming 
batchBlock.Complete(); 

그리고 그 처리의 처리됩니다. 파이프 라인에서 모든 항목 처리가 완료되면 알림을 받으려면 ActionBlockCompletion 속성을 사용하여 알림을받습니다.

actionBlock.Completion.ContinueWith(prev => {Console.WriteLine("Finished.");}).