比较C#中的求和方法

本文关键字:求和 方法 比较 | 更新日期: 2023-09-27 18:29:44

我正在处理一个使用大量求和方法的项目的一部分。这些求和方法应用于Datatable

为了测试最佳方法,我使用以下

数据表结构

class LogParser
{
     public DataTable PGLStat_Table = new DataTable();
     public LogParser()
     {
         PGLStat_Table.Columns.Add("type", typeof(string)); 
         PGLStat_Table.Columns.Add("desc", typeof(string)); 
         PGLStat_Table.Columns.Add("count", typeof(int));
         PGLStat_Table.Columns.Add("duration", typeof(decimal));
         PGLStat_Table.Columns.Add("cper", typeof(decimal));
         PGLStat_Table.Columns.Add("dper", typeof(decimal));
         PGLStat_Table.Columns.Add("occurancedata", typeof(string));  
     }       
}

以下方法用于填充表格

LogParser pglp = new LogParser();
Random r2 = new Random();
for (int i = 1; i < 1000000; i++)
{
    int c2 = r2.Next(1, 1000);
    pglp.PGLStat_Table.Rows.Add("Type" + i.ToString(), "desc" + i , c2, 0, 0, 0, " ");
}
  • 求和应用于计数列,其中更新c2的值

以下方法用于计算总和

使用计算的方法1

Stopwatch s2 = new Stopwatch();
s2.Start();
object sumObject;
sumObject = pglp.PGLStat_Table.Compute("Sum(count)", " ");
s2.Stop();
long d1 = s2.ElapsedMilliseconds;

使用Foreach循环的方法2

s2.Restart();
int totalcount = 0;
foreach (DataRow dr in pglp.PGLStat_Table.Rows)
{
   int c = Convert.ToInt32(dr["count"].ToString());
   totalcount = totalcount + c;
}
s2.Stop();
long d2 = s2.ElapsedMilliseconds;

使用Linq的方法3

s2.Restart();
var sum = pglp.PGLStat_Table.AsEnumerable().Sum(x => x.Field<int>("count"));
MessageBox.Show(sum.ToString());
s2.Stop();
long d3 = s2.ElapsedMilliseconds;

比较后的结果是

a) foreach是最快的481ms

b) 下一个是linq1016ms

c) 然后计算2253ms


查询1

我不小心在以下语句中将"c2更改为I"

 pglp.PGLStat_Table.Rows.Add("Type" + i.ToString(), "desc" + i , i, 0, 0, 0, " ");

Linq语句产生错误

算术运算导致溢出。

而Compute和Foreach循环仍然能够完成计算,尽管可能不正确。

这种行为是令人担忧的,还是我错过了指示?(计算的数字也很大)

查询2

我觉得Linq做得最快,有没有优化的方法或参数这使它表现得更好。

感谢的建议

arvind

比较C#中的求和方法

下一个是最快的和(带有预计算DataColumn和直接转换为int):

  static int Sum(LogParser pglp)
  {
    var column = pglp.PGLStat_Table.Columns["count"];
    int totalcount = 0;
    foreach (DataRow dr in pglp.PGLStat_Table.Rows)
    {
      totalcount += (int)dr[column];
    }
    return totalcount;
  }

统计:

00:00:00.1442297, for/each, by column, (int)
00:00:00.1595430, for/each, by column, Field<int>
00:00:00.6961964, for/each, by name, Convert.ToInt
00:00:00.1959104, linq, cast<DataRow>, by column, (int)

其他代码:

  static int Sum_ForEach_ByColumn_Field(LogParser pglp)
  {
    var column = pglp.PGLStat_Table.Columns["count"];
    int totalcount = 0;
    foreach (DataRow dr in pglp.PGLStat_Table.Rows)
    {
      totalcount += dr.Field<int>(column);
    }
    return totalcount;
  }
  static int Sum_ForEach_ByName_Convert(LogParser pglp)
  {
    int totalcount = 0;
    foreach (DataRow dr in pglp.PGLStat_Table.Rows)
    {
      int c = Convert.ToInt32(dr["count"].ToString());
      totalcount = totalcount + c;
    }
    return totalcount;
  }
  static int Sum_Linq(LogParser pglp)
  {
    var column = pglp.PGLStat_Table.Columns["count"];
    return pglp.PGLStat_Table.Rows.Cast<DataRow>().Sum(row => (int)row[column]);
  }

    var data = GenerateData();
    Sum(data);
    Sum_Linq2(data);
    var count = 3;
    foreach (var info in new[]
      {
        new {Name = "for/each, by column, (int)", Method = (Func<LogParser, int>)Sum},
        new {Name = "for/each, by column, Field<int>", Method = (Func<LogParser, int>)Sum_ForEach_ByColumn_Field},
        new {Name = "for/each, by name, Convert.ToInt", Method = (Func<LogParser, int>)Sum_ForEach_ByName_Convert},
        new {Name = "linq, cast<DataRow>, by column, (int)", Method = (Func<LogParser, int>)Sum_Linq},
      })
    {
      var watch = new Stopwatch();
      for (var i = 0; i < count; ++i)
      {
        watch.Start();
        var sum = info.Method(data);
        watch.Stop();
      }
      Console.WriteLine("{0}, {1}", TimeSpan.FromTicks(watch.Elapsed.Ticks / count), info.Name);
    }

好吧,您可以在linq示例(AsEnumerable)上改进一点,但这是预期的行为-linq(2对象)不能像循环一样快(使用for(var i = ...)循环而不是foreach可以做得更好)-我想您想做的是使用Linq2Sql-然后在数据库上进行聚合(sum),应该会更快-但由于您似乎不使用数据库数据。。。

查询1.

正如您在文档Enumerable.Sum扩展方法中看到的那样,在整数溢出时抛出OverflowException。Compute没有像方法2中使用的整数运算那样的功能。


更新:查询2

我觉得Linq做得最快,有没有一个优化的方法或参数可以让它表现得更好。

AFAIK,没有优化阵列求和算法的方法(不使用并行计算)。林克将foreach使用的时间增加了一倍。所以,我不认为这是linq性能的问题,而是计算效率低下的问题(请注意,查询字符串解释会有开销)。