【问题标题】:Slow performance on DataTable foreach DataColum in C# ASP.NETC# ASP.NET 中 DataTable foreach DataColum 的性能下降
【发布时间】:2020-04-15 00:11:01
【问题描述】:

在我们软件的一个版本和新出现的 beta 版本之间,循环遍历 DataTable 中所有 DataColumns 的方法存在显着延迟(该循环也在所有行的循环内)。

这是(简化但逻辑完整的)代码,两个版本都相同:

Stopwatch foretimer = Stopwatch.StartNew();
foreach (DataColumn dc in ds.Tables[0].Columns)
{
    Stopwatch foreinnertimer = Stopwatch.StartNew();
    RenderProfile.addProfile("Rows.StandardCellContents.foreEachColumn-Qty", 1);

    if (renderColumn(dc))
    {
        Stopwatch trtimer = Stopwatch.StartNew();
        temp = TokenReplacement.replaceNonCachedTokens(temp, rsa, dc, dr);
        RenderProfile.add("Rows.StandardCellContents.replaceCellTokens", trtimer.ElapsedMilliseconds);
        RenderProfile.add("Rows.StandardCellContents.replaceCellTokens-Qty", 1);

        RenderProfile.add("Rows.StandardCellContents.foreEachColumn-inner", foreinnertimer.ElapsedMilliseconds);
    }
    RenderProfile.add("Rows.StandardCellContents.foreEachColumn-inner-ALL", foreinnertimer.ElapsedMilliseconds);
}
RenderProfile.add("Rows.StandardCellContents.foreEachColumn", foretimer.ElapsedMilliseconds);

TokenReplacement.replaceNonCachedTokens 中的底层代码有一些变化,但配置文件时间并没有明显不同)

这些示例适用于相同的输入,它有 1000 行和 24 列,其中 19 列被“渲染”。

这会在旧版本上生成这些配置文件值:

 Rows-Qty:1000
 Rows.StandardCellContents.foreEachColumn-Qty:24000
 Rows.StandardCellContents.replaceCellTokens:14ms
 Rows.StandardCellContents.replaceCellTokens-Qty:19000
 Rows.StandardCellContents.foreEachColumn-inner:14ms
 Rows.StandardCellContents.foreEachColumn-inner-ALL:14ms
 Rows.StandardCellContents.foreEachColumn:2032ms

以及新版本上的这些配置文件值:

 Rows-Qty:1000
 Rows.StandardCellContents.foreEachColumn-Qty:24000
 Rows.StandardCellContents.replaceCellTokens:59ms
 Rows.StandardCellContents.replaceCellTokens-Qty:19000
 Rows.StandardCellContents.foreEachColumn-inner:66ms
 Rows.StandardCellContents.foreEachColumn-inner-ALL:67ms
 Rows.StandardCellContents.foreEachColumn:9174ms

这怎么可能? 不幸的是,即使在旧的(更快的)版本中,仅对 DataColumns 的迭代 (Rows.StandardCellContents.foreEachColumn) 大约需要 2 秒,但绝对是奇怪的是新版本一直是+7-8秒!!

它们都在相同版本的 .NET (4.0) 上运行。我在我们所做的更新中找不到任何会改变 DataTable 结构的内容。是否有与 DataSet/DataTable 相关的内容可能会减慢所有列上的 for each 循环??

非常感谢任何有关如何进一步分析此问题的指导或建议。

【问题讨论】:

  • @mjwills 我不认为您没有看到涉及的代码.. 我想您必须相信我的话,所涉及的 2 个数据表具有相同的编号行,相同的列,以及所有这些单元格中的相同数据.. 但我向你保证他们会这样做。仅使用我展示的代码,是否清楚简单的 foreach 迭代在新版本上花费了 7 秒以上?我想我正在寻找围绕 DataTable 和 DataColumn 集合的任何“已知性能陷阱”,或者关于如何进一步挖掘的建议。
  • 验证它是foreach 的简单方法是在不执行任何循环的情况下对foreach 计时——将代码注释为renderColumnTokenReplacement.replaceNonCachedTokens
  • @ilasno 您是否可以使用一些性能分析工具来分析您的应用程序,例如使用dotTrace JetBrains。如果您是,查看性能快照会很有帮助。即使您没有dotTrace 的许可证,您也可以下载并使用试用版 30 天。
  • renderColumn() 是做什么的?会不会和老版本不一样?
  • 好吧,我觉得很害羞.. 我认为我的计时器和时间记录语句的战略布局是把责任直接归咎于实际的迭代,但这似乎是一个错误的假设。我仍然不确定为什么Rows.StandardCellContents.foreEachColumn-inner-ALL 没有显示更多时间,因为它应该对每次迭代的时间求和.. 但是当我注释掉foreach 中的所有代码时,缓慢的性能就会消失。我正在深入挖掘,感谢所有给我时间的人。 @HereticMonkey 如果您想添加您的评论作为答案,我会接受!

标签: c# asp.net foreach datatable


【解决方案1】:

好吧,这并不能真正回答问题,但要诊断问题是否确实是迭代而不是其他地方,我将注释除迭代之外的所有代码:

Stopwatch foretimer = Stopwatch.StartNew();
foreach (DataColumn dc in ds.Tables[0].Columns)
{
    Stopwatch foreinnertimer = Stopwatch.StartNew();
    RenderProfile.addProfile("Rows.StandardCellContents.foreEachColumn-Qty", 1);

    //if (renderColumn(dc))
    {
        //Stopwatch trtimer = Stopwatch.StartNew();
        //temp = TokenReplacement.replaceNonCachedTokens(temp, rsa, dc, dr);
        //RenderProfile.add("Rows.StandardCellContents.replaceCellTokens", trtimer.ElapsedMilliseconds);
        //RenderProfile.add("Rows.StandardCellContents.replaceCellTokens-Qty", 1);

        RenderProfile.add("Rows.StandardCellContents.foreEachColumn-inner", foreinnertimer.ElapsedMilliseconds);
    }
    RenderProfile.add("Rows.StandardCellContents.foreEachColumn-inner-ALL", foreinnertimer.ElapsedMilliseconds);
}
RenderProfile.add("Rows.StandardCellContents.foreEachColumn", foretimer.ElapsedMilliseconds);

这会将正在计时的内容限制为 foreach(以及 StopwatchRenderProfile 语句的开销希望可以忽略不计)。

我猜renderColumnTokenReplacement 中的某些内容在两个版本之间发生了变化(不一定在您的代码中——可能在框架代码中,尽管这种幅度的性能回归是不寻常的)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多