为啥 MongoDB Java 驱动程序在条件中使用随机数生成器?

Posted

技术标签:

【中文标题】为啥 MongoDB Java 驱动程序在条件中使用随机数生成器?【英文标题】:Why does the MongoDB Java driver use a random number generator in a conditional?为什么 MongoDB Java 驱动程序在条件中使用随机数生成器? 【发布时间】:2013-05-25 20:20:18 【问题描述】:

我在this commit 中看到了MongoDB's Java Connection driver 的以下代码,起初它似乎是某种玩笑。下面的代码是做什么的?

if (!((_ok) ? true : (Math.random() > 0.1))) 
    return res;

(编辑:代码has been updated since发布此问题)

【问题讨论】:

哪一部分让你感到困惑? 我认为这很混乱。此代码在 catch 块中执行! @MarkoTopolnik:是吗?可以更清楚地写成if (!ok || Math.random() < 0.1)(或类似的东西)。 github.com/mongodb/mongo-java-driver/commit/… 你不是第一个,请参阅该行的评论 @msangel 那些家伙似乎在批评逻辑,而不是编码风格。 【参考方案1】:

在检查了该行的历史之后,我的主要结论是工作中存在一些不称职的编程。

    那条线无缘无故地令人费解。一般形式

    a? true : b
    

    对于boolean a, b 等价于简单

    a || b
    

    周围的否定和过多的括号使事情进一步复杂化。请记住De Morgan's laws,这段代码相当于

    if (!_ok && Math.random() <= 0.1)
      return res;
    

    originally introduced this logic 的提交

    if (_ok == true) 
      _logger.log( Level.WARNING , "Server seen down: " + _addr, e );
     else if (Math.random() < 0.1) 
      _logger.log( Level.WARNING , "Server seen down: " + _addr );
    
    

    ——另一个编码不称职的例子,但请注意颠倒的逻辑:如果_ok 或其他10% 的情况,则记录事件,而2 中的代码。 10% 的时间返回并记录 90% 的时间。所以后来的提交不仅破坏了清晰度,而且破坏了正确性本身。

    我认为在您发布的代码中,我们实际上可以看到作者打算如何将原始if-then 以某种方式从字面上转换为早期return 条件所需的否定。但后来他搞砸了,通过反转不等号插入了一个有效的“双重否定”。

    撇开编码风格问题不谈,随机日志记录本身就是一种非常可疑的做法,尤其是因为日志条目没有记录其自身的特殊行为。显然,其目的是减少对同一事实的重述:服务器当前已关闭。适当的解决方案是仅记录服务器状态的更改,而不是每个观察结果,更不用说随机选择 10% 的此类观察结果。是的,这需要更多的努力,所以让我们来看看。

我只能希望所有这些从检查仅三行代码中积累的无能证据不能公平地说明整个项目,并且这项工作将得到清理尽快起来。

【讨论】:

此外,据我所知,这似乎是 MongoDB 的官方 10gen Java 驱动程序,所以除了对 Java 驱动程序有意见外,我认为它还给了我对代码的意见MongoDB的 几行代码分析得很好,我可能会把它变成一个面试问题!您的第四点是该项目存在根本性问题的真正关键(其他可能被视为不幸的程序员错误)。 @ChrisTravers 它 mongo 的官方 mongo java 驱动程序。【参考方案2】:

https://github.com/mongodb/mongo-java-driver/commit/d51b3648a8e1bf1a7b7886b7ceb343064c9e2225#commitcomment-3315694

11 小时前 gareth-rees:

大概的想法是只记录大约 1/10 的服务器故障(从而避免大量垃圾日志),而不会产生维护计数器或计时器的成本。 (但维护一个计时器肯定是负担得起的吗?)

【讨论】:

不要吹毛求疵,而是:1/10 的时间它会返回 res,所以它会记录其他 9/10 次。 @Supericy 这绝对不是吹毛求疵。这只是这个人糟糕的编码习惯的更多证据。【参考方案3】:

添加一个初始化为负1的类成员:

  private int logit = -1;

在try块中,进行测试:

 if( !ok && (logit = (logit + 1 ) % 10)  == 0 )  //log error

这总是记录第一个错误,然后是每十个后续错误。逻辑运算符“短路”,因此 logit 只会在实际错误时递增。

如果您想要所有错误的第一个和第十个,无论连接如何,都将 logit 类设为静态而不是成员。

如前所述,这应该是线程安全的:

private synchronized int getLogit() 
   return (logit = (logit + 1 ) % 10);

在try块中,进行测试:

 if( !ok && getLogit() == 0 )  //log error

注意:我不认为扔掉 90% 的错误是个好主意。

【讨论】:

【参考方案4】:

我以前见过这种东西。

有一段代码可以回答来自另一段“黑匣子”代码的某些“问题”。如果它无法回答它们,它会将它们转发到另一段非常慢的“黑盒”代码。

所以有时会出现以前看不见的新“问题”,它们会成批出现,比如连续出现 100 个。

程序员对程序的运行方式很满意,但如果可能发现新问题,他想在未来通过某种方式改进软件。

因此,解决方案是记录未知问题,但事实证明,有 1000 个不同的问题。日志太大了,加快这些速度没有任何好处,因为它们没有明显的答案。但每隔一段时间,就会出现一批可以回答的问题。

由于日志变得太大,并且日志记录妨碍了记录真正重要的事情,他得到了这个解决方案:

仅随机记录 5%,这将清理日志,而从长远来看,仍会显示可以添加哪些问题/答案。

因此,如果发生未知事件,在随机数量的这些情况下,它会被记录。

我认为这与您在此处看到的相似。

我不喜欢这种工作方式,所以我删除了这段代码,只是记录了这些 消息到不同的文件,因此它们都存在,但不会破坏常规日志文件。

【讨论】:

除了我们在这里讨论的是数据库驱动程序......错误的问题空间,IMO! @StevenSchlansker 我从来没有说过这是一个好习惯。我删除了这段代码,只是将这些消息记录到不同的文件中。

以上是关于为啥 MongoDB Java 驱动程序在条件中使用随机数生成器?的主要内容,如果未能解决你的问题,请参考以下文章

mongoDB在java中怎么根据内嵌文档条件查询

mongodb数据库批量插入海量数据时为啥有少部分数据丢失

求教mongodb大神,在java中怎么以时间为条件查询

为啥在 MongoDB 中缩放时自动增量模式不好?

明确MangoDB在企业中应用

在 Django 中使迁移有条件