【问题标题】:How do I mitigate the risk of an infinite loop?如何降低无限循环的风险?
【发布时间】:2013-04-30 16:13:39
【问题描述】:

我们正在查看我们的代码以尝试识别高 CPU 使用率,并且我正在查看我们使用 while 循环的几个区域。我想在下面显示的代码中冒无限循环的风险,但我不确定最好的解决方案是什么。

IDictionaryEnumerator codeEnumerator = Resources.Error_Codes.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true).GetEnumerator();
IDictionaryEnumerator messageEnumerator = Resources.Error_Messages.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true).GetEnumerator();


bool codeDone = false;
bool messageDone = false;

while (codeEnumerator.MoveNext() && !codeDone)
{
    string value = codeEnumerator.Value.ToString();
    if (value == failedResponse.Code.ToString())
    {
        key = codeEnumerator.Key.ToString();
        codeDone = true;
    }
}

while (messageEnumerator.MoveNext() && !messageDone)
{
    if (messageEnumerator.Key.ToString() == key)
    {
        message = messageEnumerator.Value.ToString();
        messageDone = true;
    }
}

【问题讨论】:

  • 请在下次格式化您的代码时更加小心,尽可能避免水平滚动。让代码从屏幕的一半开始是没有意义的。
  • 您是担心序列是无限序列,还是担心即使序列是有限的代码也会永远运行?
  • 被枚举的每个资源集中的资源都是有限的。在上面的代码中,它们甚至不可能成为无限循环,但我想确定一下。
  • 首先让代码正确。我在该代码中没有看到任何 Dispose() 调用。 您需要处理枚举数;如果你不这样做,那么迭代器块中的 finally 块将永远不会运行。我会考虑重写这个不正确的代码以使用序列运算符;这将使代码正确、更短、更易于阅读。
  • 此外:您为什么要通过循环搜索字典字典的全部意义在于您可以直接搜索它,这就是它被称为字典的原因。无限循环是您遇到的最少的问题;此代码存在严重缺陷。

标签: c# infinite-loop enumerator


【解决方案1】:

假设底层序列是有限的,而不是无限的,(which you have said is the case) 那么循环不会永远运行。

最终您可以确定会发生以下情况之一:

  1. if 将对给定项目为真,从而设置布尔值并跳出循环。

  2. 您将前进到序列的末尾,从而导致MoveNext 为假。

  3. 会从某个地方抛出异常,例如从被另一个线程修改的底层集合、序列中的空值或其他任何地方抛出异常。由于您没有尝试/捕获,这将使您脱离循环。

特别是,由于循环的每次迭代必须推进迭代器(由于MoveNext),你可以确定你最终会结束。

【讨论】:

    【解决方案2】:

    查看您的代码并试图弄清楚您的字典的实际名称是什么,我认为您正在寻找这样的东西:

    var key = Error_Codes.FirstOrDefault(kvp => kvp.Value.ToString = 
        failedResponse.Code.ToString()).Select(kvp => kvp.Key);
    string message = string.Empty;
    if(null != key)
        message = Error_Messages[key];
    

    这假设您的字典是 Error_Codes 和 Error_Messages。

    正如 Eric 在 cmets 中指出的那样,您使用迭代器和字典的方式存在问题。这消除了迭代器问题,但这仍然不是使用字典的理想方式。

    如果您有一个唯一的错误消息列表和错误代码键,那么您可以有一个将两者映射在一起的字典。或者,您可以将字典与字典键的公共键集以及错误代码和错误消息的元组组合为字典值。

    【讨论】:

      【解决方案3】:

      如果循环花费的时间超过 x 时间,您可以启动一个计时器/其他线程,将第二个条件设置为 false。但我也不认为这是一个干净的解决方案。

      【讨论】:

      • 我们正在经历和修改代码的部分原因是为了减少整体 CPU 使用率,所以我不确定从长远来看产生额外的计时器或线程是否会有所帮助。谢谢你!
      【解决方案4】:

      您可以在 while 循环中添加一个倒计时的计数器。将计数器实际高设置为 100 左右的值,当计数器达到零时,退出循环。这意味着它可能会在操作完全执行之前终止,但这意味着它最终会退出。

      【讨论】:

        猜你喜欢
        • 2014-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-03
        • 1970-01-01
        相关资源
        最近更新 更多