无限循环。 或者:可能出错的任何事情都可以。

一位智者曾经说过:

任何可能出错的事情都会

墨菲

一些程序员是智者,因此,明智的程序员曾经说过:

优秀的程序员是在横穿单向街道之前会双向看待的人。

道格·林德Doug Linder)

在一个完美的世界中,事情按预期进行,您可能会认为保持消耗直到最后是一个好主意。 因此,可以在每个代码库中找到以下模式:

Java

for (;;) {
    // something
}

C

while (1) {
    // something
}

基本知识

10 something
20 GOTO 10

想看证明吗? 在github上搜索while(true)并查看匹配项的数量: https : //github.com/search? q=while+true&type =Code

永远不要使用无限循环

在计算机科学领域,围绕“停止问题”的话题进行了非常有趣的讨论。 阿兰·图灵很久以前就证明了停顿问题的实质是,它确实还不确定。 尽管人们可以快速评估以下程序永远不会停止:

for (;;) continue;

…并且以下程序将始终停止:

for (;;) break;

……计算机无法决定这些事情,即使是经验丰富的人,在查看更复杂的算法时也可能无法立即做出决定。

边干边学

在jOOQ中,我们最近通过困难的方式了解了停止问题:这样做。

在解决问题#3696之前,我们解决了SQL Server JDBC驱动程序中的错误(或缺陷)。 该错误导致未正确报告SQLException链,例如,当以下触发器引发多个错误时:

CREATE TRIGGER Employee_Upd_2  ON  EMPLOYEE FOR UPDATE
AS 
BEGIN

    Raiserror('Employee_Upd_2 Trigger called...',16,-1)
    Raiserror('Employee_Upd_2 Trigger called...1',16,-1)
    Raiserror('Employee_Upd_2 Trigger called...2',16,-1)
    Raiserror('Employee_Upd_2 Trigger called...3',16,-1)
    Raiserror('Employee_Upd_2 Trigger called...4',16,-1)
    Raiserror('Employee_Upd_2 Trigger called...5',16,-1)

END
GO

因此,我们显式使用了这些SQLExceptions ,以便jOOQ用户对所有数据库都具有相同的行为:

consumeLoop: for (;;)
    try {
        if (!stmt.getMoreResults() && 
             stmt.getUpdateCount() == -1)
            break consumeLoop;
    }
    catch (SQLException e) {
        previous.setNextException(e);
        previous = e;
    }

这对我们的大多数客户都有效,因为由此报告的异常链可能是有限的,而且可能也很小。 即使上面的触发器示例也不是真实示例,因此报告的实际错误数可能在1-5之间。

我只是说…… “可能”吗?

就像我们最初的智者所说:这个数字可能在1-5之间。 但是也可能是1000。或者是1000000。或更糟糕的是,是无限的。 与问题#3696的情况一样,当客户将jOOQ与SQL Azure一起使用时。 因此,在一个完美的世界中,不能报告无限数量的SQLException ,但这不是一个完美的世界,SQL Azure也有一个错误(可能仍然存在),该错误一次又一次报告相同的错误,最终导致jOOQ创建了一个巨大的SQLException链,从而产生了OutOfMemoryError ,这可能比无限循环更好。 至少该异常易于检测和解决。 如果循环无限运行,则服务器可能已被我们所有客户的用户完全阻止。

现在,解决方法基本上就是这个:

consumeLoop: for (int i = 0; i < 256; i++)
    try {
        if (!stmt.getMoreResults() && 
             stmt.getUpdateCount() == -1)
            break consumeLoop;
    }
    catch (SQLException e) {
        previous.setNextException(e);
        previous = e;
    }

忠实于俗语:

640 KB对于任何人都应该足够

唯一的例外

因此,正如我们之前所见,这个令人尴尬的示例表​​明, 任何可能出错的事情都可以做到 。 在可能发生initeite循环的情况下,请注意,这种错误将使整个服务器瘫痪。

加州理工学院的喷气推进实验室已将此成为其编码标准的基本规则

规则3(循环界限)

所有循环在最大循环迭代次数上应具有静态可确定的上限。 静态符合性检查工具应有可能确认界限的存在。 允许在每个接收或处理请求的任务或线程中使用单个非终止循环的异常。 这样的服务器循环应使用C注释:/ * @ non-terminated @ * /。

因此,除了极少数例外,您永远都不要通过不提供循环迭代的上限来使代码面临无限循环的风险(关于递归,顺便说一句)。

结论

今天检查您的代码库,查找while (true)for (;;)任何可能while (true) do {} while (true); 和其他声明。 仔细检查这些语句,看看它们是否可以停止-例如,使用breakthrowreturncontinue (外部循环)。

您或之前编写该代码的人可能像我们一样天真,相信……

……哦,这永远不会发生, 因为,当您认为什么也不会发生时,您会知道会发生什么

翻译自: https://www.javacodegeeks.com/2015/01/infinite-loops-or-anything-that-can-possibly-go-wrong-does.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值