使用c#任务从SQL获取行

使用c#任务从SQL获取行,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,我的桌子上大约有300万行。我有一个控制台应用程序来获取所有行并处理这些行。我想使用TPL一次获取1000行并执行我的处理逻辑。我可以有以下逻辑,在ProcessRowsForPage方法中,我将根据页码获取记录 int totalRecordsCount = GetCount(); int pagecount = totalRecordsCount/1000; for (int j= 0; j <= pagecount; j++) { var pageNo= j; var

我的桌子上大约有300万行。我有一个控制台应用程序来获取所有行并处理这些行。我想使用TPL一次获取1000行并执行我的处理逻辑。我可以有以下逻辑,在ProcessRowsForPage方法中,我将根据页码获取记录

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);
 }
int totalRecordsCount=GetCount();
int pagecount=totalRecordsCount/1000;
对于(int j=0;j
{
ProcessRowsForPage(页码);
});
任务。添加(t);
}

可能是,这很奇怪,但是有没有一种方法可以在不计算总数的情况下创建任务。我想使用类似do while循环的方法,在没有更多行可提取时停止创建任务

如果使用某种类型的池,您可以这样做,而不是生成数百万个任务,这是一个坏主意

在一个数组中创建3个(例如)任务,并启动它们

当一个任务完成时,如果有更多行,请将其重新设置

一旦任务不再返回数据,停止设置,等待所有任务完成,然后完成

例如:

TASK1 > GetNext100Rows(0)
TASK2 > GetNext100Rows(100)
TASK3 > GetNext100Rows(200)
如果Task2首先完成,请重新启动它:

TASK1 > GetNext100Rows(0) [Processing]
TASK2 > GetNext100Rows(300) [Processing]
TASK3 > GetNext100Rows(200) [Processing]
继续重新启动所有已完成的任务,每次增加100

最后,当任务不再返回数据时,等待所有剩余线程完成


这要求您的任务能够返回或指示它没有更多的数据,例如通过设置标志变量或返回对象。

如果您使用某种类型的池,您可以这样做,而不是产生可能数以百万计的任务,这是一个坏主意

在一个数组中创建3个(例如)任务,并启动它们

当一个任务完成时,如果有更多行,请将其重新设置

一旦任务不再返回数据,停止设置,等待所有任务完成,然后完成

例如:

TASK1 > GetNext100Rows(0)
TASK2 > GetNext100Rows(100)
TASK3 > GetNext100Rows(200)
如果Task2首先完成,请重新启动它:

TASK1 > GetNext100Rows(0) [Processing]
TASK2 > GetNext100Rows(300) [Processing]
TASK3 > GetNext100Rows(200) [Processing]
继续重新启动所有已完成的任务,每次增加100

最后,当任务不再返回数据时,等待所有剩余线程完成


这要求您的任务能够返回或指示它没有更多的数据,例如通过设置标志变量或返回对象。

对于这种情况,您最好选择

为此,您需要以下组件:

  • 一个
    SqlDataReader
    或其他类型的东西,可以从数据库中传输数据
  • 批处理大小为1000的a
  • 将调用
    ProcessRows
    方法的
现在,要创建处理管道,请将块链接在一起:

batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true });
之后,从
dataReader
Post
行到
BatchBlock

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();
这将负责处理。如果希望在管道处理完所有项目后收到通知,请使用
ActionBlock
Completion
属性获得通知

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

在这种情况下,你最好接受

为此,您需要以下组件:

  • 一个
    SqlDataReader
    或其他类型的东西,可以从数据库中传输数据
  • 批处理大小为1000的a
  • 将调用
    ProcessRows
    方法的
现在,要创建处理管道,请将块链接在一起:

batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true });
之后,从
dataReader
Post
行到
BatchBlock

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();
这将负责处理。如果希望在管道处理完所有项目后收到通知,请使用
ActionBlock
Completion
属性获得通知

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

如果没有计数,任务如何知道它已到达最后一页?它将不得不询问上一个任务,但上一个任务可能尚未完成。是的。我认为,除非我知道总计数,否则我认为不可能创建多个任务。您可以使用ConcurrentQueue,一次出列1000个。如果没有计数,任务如何知道它已到达最后一页?它将不得不询问上一个任务,但上一个任务可能尚未完成。是的。我认为,除非我知道总数,否则我认为不可能创建多个任务。您可以使用ConcurrentQueue,一次出列1000个任务。