ChatGPT解决这个技术问题 Extra ChatGPT

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

我在 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 那些人似乎在批评逻辑,而不是编码风格。

E
Erik Schierboom

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

那条线是无端令人费解的。一般形式a? true : b for boolean a, b 等价于简单的 a || b 周围的否定和过多的括号使事情进一步复杂化。记住德摩根定律,这是一个微不足道的观察,这段代码相当于 if (!_ok && Math.random() <= 0.1) return res;最初引入此逻辑的提交有 if (_ok == true) { _logger.log( Level.WARNING , "Server seen down:" + _addr, e ); } else if (Math.random() < 0.1) { _logger.log( Level.WARNING , "服务器已关闭:" + _addr ); } — 另一个不称职的编码示例,但请注意相反的逻辑:这里如果 _ok 或在 10% 的其他情况下记录事件,而 2. 中的代码返回 10% 的时间并记录 90% 的时间。所以后来的提交不仅破坏了清晰度,而且破坏了正确性本身。我认为在您发布的代码中,我们实际上可以看到作者打算如何将原始的 if-then 以某种方式从字面上转换为早期返回条件所需的否定。但后来他搞砸了,通过反转不等号插入了一个有效的“双重否定”。撇开编码风格问题不谈,随机日志本身就是一种非常可疑的做法,尤其是因为日志条目没有记录其自身的特殊行为。显然,其目的是减少对同一事实的重述:服务器当前已关闭。适当的解决方案是只记录服务器状态的变化,而不是每个观察结果,更不用说随机选择 10% 的观察结果了。是的,这需要更多的努力,所以让我们看看。

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


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

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

11 小时前由 gareth-rees:

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


不是吹毛求疵,而是:1/10 的时间它会返回 res,所以它会记录其他 9/10 次。
@Supericy 这绝对不是挑剔。这只是这个人糟糕的编码实践的更多证据。
t
tpdi

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

  private int logit = -1;

在 try 块中,进行测试:

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

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

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

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

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

在 try 块中,进行测试:

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

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


N
Neeme Praks

我以前见过这种东西。

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

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

程序员对程序的工作方式很满意,但如果可能发现新的问题,他希望将来可以通过某种方式改进软件。

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

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

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

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

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

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


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