2012-03-11 93 views
3

我遇到了一个循环时间问题,就像数据库中的100万个潜在行循环一样。我基本上将行拖入一个DataTable并循环它们,但速度变慢。那里有什么替代方案?我可以将这些行分成两万块一块。我可以在C#中使用并行处理吗?基本上,代码遍历每个匹配某个查询的潜在记录,并试图找出它是否是合法的条目。这就是为什么每个记录都需要单独访问。一个对象的记录可能达到1000万行。方法似乎是多台计算机中的并行处理,或多核内的单机中的PP,或某种数据结构/方法的改变?通过很多行循环

任何意见,想法和猜测有助于使这个快速和合理?

回答

2

第一关:不要使用DataTable运营这样的

  • 它的速度慢
  • 它消耗太多内存
  • ,你需要等待很长的时间,你可以真正开始之前处理数据
    • 在此期间,额外的内核无所事事,因为将数据读入DataTable未被隔离。
    • 同时在读取数据时,CPU通常几乎没有得到充分利用,因为网络或其他I/O延迟通常是主要因素。

如此反复:不要像​​这些操作使用DataTable

改为使用DataReader。这允许您立即开始消费/处理数据,而不是等待它加载。最简单的版本将是(对MS SQL Server示例):

var command = new SqlCommand() 
{ 
    CommandText = "SELECT * FROM Table"; 
    Connection = new SqlConnection("InsertConnectionString"); 
}; 

using(var reader = command.ExecuteReader()) 
{ 
    while(reader.Read()) 
    { 
    var values = new object[reader.FieldCount]; 
    reader.GetValues(values); 

    // process values of row 
    } 
} 

读者会在执行你的处理代码,这意味着没有更多的行从数据库中读取被阻止。
如果处理代码很重,可能值得使用Task库创建执行检查的任务,这将使您能够使用多个内核。但是,创造一个Task的开销,如果一个Task没有包含足够的“工作”,你可以批量几排在一起:

public void ReadData() 
{ 
    var taskList = new List<Task<SomeResultType>>(); 

    var command = new SqlCommand() 
    { 
    CommandText = "SELECT * FROM Table"; 
    Connection = new SqlConnection("InsertConnectionString"); 
    }; 
    using(var reader = command.ExecuteReader()) 
    { 
    var valueList = new List<object[]>(100); 
    while(reader.Read()) 
    { 
     var values = new object[reader.FieldCount]; 
     reader.GetValues(values); 

     valueList.Add(values); 

     if(valueList.Count == 100) 
     { 
     var localValueList = valueList.ToList(); 
     valueList.Clear(); 

     taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(localValueList)); 
     } 
    } 
    if(valueList.Count > 0) 
     taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(valueList)); 
    } 

    // this line completes when all tasks are done 
    Task.WaitAll(taskList.ToArray()); 
} 

public SomeResultType Process(List<object[]> valueList) 
{ 
    foreach(var vals in valueList) 
    { 
    // put your processing code here, be sure to synchronize your actions properly 
    } 
} 
  • 批量大小(目前为100)取决于实际正在完成处理,可能需要进行调整。
  • 同步拥有它自己的挑战,你必须非常小心地共享资源
+0

好的解释但我有一些问题: 1-哪个更好,你建议的解决方案或者 做出多个任务,每个任务都使用SQLReader从数据库中读取一系列行(例如,基于寻呼),特别是在结果处理的情况下不是很重。 2-是否在任务BackgroundWork之间的性能有显着差异? – 2015-05-13 11:03:09

0

我建议并联一个双核机循环,并尝试使用与通用列出了每个循环,我认为这可能使你的过程更快。