2016-10-14 2 views
1

テーブルには約300万行があります。私はすべての行を取得し、それらの行を処理するコンソールアプリケーションを持っています。私は一度に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つのタスク(たとえば、タスク)を1つのアレイに作成し、すべてのタスクを開始します。

1つのタスクが完了すると、さらに行がある場合は、もう一度それを設定します。

タスクでデータが返されなくなると、設定をやめ、すべてのタスクが完了するのを待ってから完了します。

例: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
  • でデータベース
  • BatchBlockからデータをストリーミングできるものの他のいくつかの並べ替えを呼び出しますActionBlockProcessRowsメソッド

ここで、処理パイプラインを作成するには、一緒に:その後

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

BatchBlockにごdataReaderPost行から:

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.");}).