【问题标题】:Foreach loop takes a very long time to break out ofForeach 循环需要很长时间才能摆脱
【发布时间】:2011-02-03 01:30:28
【问题描述】:

抓取网页,包含大约 250 个表格分区。 使用 WatiN 和 WatinCSSSelectors

首先我选择所有属性为 'width=90%' 的 td 标签:

var allMainTDs = browser.CssSelectAll("td[width=\"90%\"]");

然后我创建一个 foreach 循环,将 var 的内容粘贴到一个列表中。 int 用于检查循环当前所在的 td 标签。

List<Element> eletd = new List<Element>();
int i = 0;
foreach (Element td in allMainTDs)
{
    eletd.Add(td);
    i++;
    Console.WriteLine(i);                    
}

它很快就到达了第 250 个标签。但是接下来大约需要 6 分钟(使用 StopWatch 对象计时)才能进入下一条语句。这里发生了什么?

【问题讨论】:

  • @MHTn 什么是next statement
  • 没关系,目前我有int i = 0;,只是在那里放一个断点。问题是在 foreach 循环之后需要 AGES 才能到达下一行代码,在本例中为 int i =0;
  • CssSelectAll 返回的集合的枚举数的 Dispose 方法很可能会占用您的时间。你可以在分析器下运行它吗?
  • 您是否尝试过在遇到延迟时中断以查看您在堆栈中的位置?听起来有些东西阻碍了第 250 个元素的枚举。
  • @Martinho Fernandes - 我刚刚下载了 ANTS profiler 试用版,但我不确定要看什么。目前,foreach 循环约占总时间成本的 84%。然而。我发现作为 CSSSelector 的一部分对 Watin 方法的调用似乎是这个耗时过程的最大份额......也许我会坚持使用良好的旧循环和 if 语句......@Justin Morgan - 我已经击中暂停,它只是以绿色突出显示 foreach 循环(特别是“in”字)。不知道这意味着什么。

标签: c# foreach watin enumeration


【解决方案1】:

你可以试试这个:

var eletd = new List<Element>(allMainTDs);

【讨论】:

  • 列表构造函数也将遍历 allMainTDs。我看不出这有什么帮助,但它确实使代码更简单。
  • 感谢这个快捷方式,它和foreach循环的效果和时间消耗一样,但是读起来更简单!
【解决方案2】:

foreach 循环大致相当于以下代码(不完全正确,但足够接近):

IEnumerator<T> enumerator = enumerable.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        T element = enumerator.Current;
        // here goes the body of the loop
    }
}
finally
{
    IDisposable disposable = enumerator as System.IDisposable;
    if (disposable != null) disposable.Dispose();
}

您描述的行为指向此代码的清理部分。 CssSelectAll 调用结果的枚举器可能有一个繁重的 Dispose 方法。您可以通过将循环替换为上述代码来确认这一点,并省略 finally 块,或设置断点以确认 Dispose 需要永远运行。

【讨论】:

  • 感谢此代码。在找到第 250 个表 div 后,它实际上挂在 while (enumerator.MoveNext()) 上。通常的 6 分钟后,我们到达 finally 块,Disposal 发生一次,然后我可以继续。 ANTS Profiler 显示堆栈上的最后一次调用是 WatiN.Core.Native.InternetExplorer.IEEElement+&lt;&gt;c__DisplayClassc.&lt;WaitUntilElementAvailable&gt;b__b()
  • @MHTri:哦,所以需要很长时间才能确定没有更多的 tds 可以找到。除非文档很大(我的意思是太大),否则我会将此作为可能的错误报告给 WatiN 团队。或者它可能与 IE 相关...
  • 我已经开始尝试不同的解决方案,但感谢您的帮助!
【解决方案3】:

如果你在 .net 4.0 下并且你的执行环境允许并行,你可能应该尝试一下

  Prallel.ForEach(..);

【讨论】:

  • 这听起来很简洁,但在继续之前我需要列表数据。不过,感谢您引起我的注意。
  • @So 那么另一种思路是考虑为生成 allMainTD 的源实现自定义迭代器,您必须自己进行 DOM 遍历,但可能值得一试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 2019-02-23
  • 2013-10-11
  • 2012-12-04
  • 2012-12-03
相关资源
最近更新 更多