实际上,我认为是一个灵活的负载平衡的想法并不糟糕,具体取决于谁可以收集关键信息并使用它。
因为它基于Dubbo,在调试过程中,我写道我看到了这个地方:
org.apache.dubbo.rpc.protocol.abstractinvoker#waitforresultifsync
首先查看我构架的这一行代码。在iysncresult中有一个完整的未来。它随超时时间调用get()方法。超时时间为integer.max_value。从理论上讲,效果等同于get()方法。
从我的直观角度来看,这里的get()方法甚至更好地理解都不应该存在问题。
但是为什么不使用get()方法呢?
实际上,该方法的注释是出于原因而写的,恐怕像我这样的人会有这样的问题:
这些抓住我眼睛的话是:
表现严重。
表现认真下降。
可能是我们必须致电而不是get()方法,因为事实证明该方法会导致性能大幅下降。
对于Dubbo而言,Waitforresultifsync方法是主要链接上的一种方法。我个人认为,可以说,可以说,有90%以上的请求将会出现这种阻止结果的方法。将影响Dubbo的表现。
Dubbo作为中间件,可能会以各种不同的JDK版本运行。对于特定的JDK版本,此优化确实对提高性能非常有帮助。
即使我们不说Dubbo,当我们使用完整的未图时,get()方法是我们经常使用的方法。
此外,我对此方法的调用链接非常熟悉。
因为我两年前写的第一篇公共帐户文章被讨论了Dubbo的异步转换,“ Dubbo 2.7新功能的异步转换”
当时,这个代码绝对不是这样,至少没有这样的提示。
因为如果您有此提示,我必须在第一次编写它时注意到它。
果然,我去了它。尽管图片已经模糊,但我仍然可以隐约地看到它。曾经调用的get()方法:
我也称其为最“ SAO”的代码行。
因为该行的代码是Dubbo异步的关键代码,以同步。
这只是前面的引号。本文不会编写Dubbo相关的知识点。
get()完整未来的问题是什么?
放心,面试绝对不会接受采访。只是在您知道这一点之后,您的JDK版本在修复之前就无法修复。编写代码时,您可以注意它。
在该方法调用相同通知的地方学习Dubbo,并直接推动GE。
或者,当您不小心看到其他人以这种方式写作时,请轻轻地说:这里可能存在性能问题,您可以找出答案。
根据Dubbo注释中的信息,我不知道问题是什么,但是我知道在哪里可以找到问题。
这种问题必须记录在OpenJDK的错误列表中,因此第一站是在此处搜索以搜索关键字:
https://bugs.openjdk.java.net/projects/jdk/issues/
一般来说,这是一些旧的错误,需要搜索半天的时间才能找到所需的信息。
但是,这次我很幸运,第一个突然出现的是我想要的。我有点不习惯。这是传奇的国庆礼物吗?我不敢考虑。
标题是:完整未来的绩效提高。
其中提到的数字8227019的错误。
https://bugs.openjdk.java.net/browse/jdk-8227019
让我们看一下这个错误所描述的内容。
标题是翻译的,这意味着完整的future.waitingget方法中有一个循环。这个周期称为运行时。可瓦布尔处理器方法。此方法经常调用,因此不好。
在详细说明中,它提到了另一个错误号8227006。此错误描述了为什么经常致电可用处理器不好,但我们首先按下它。
他提到的第一次研究这样的代码:
他说,在等待网中,我们去看看发生了什么。
但是我本地的JDK版本是1.8.0_271,其WaitchGet源代码是:
java.util.concurrent.completablefuture#waitchget
无论这些行是什么意思,我都发现我没有看到错误中提到的代码。我只看到了。尽管旋转称为该方法,但该字段是通过静态和最终方法修改的,并且在描述“经常调用”的错误中没有错误。
所以我意识到我的版本是错误的。这应该是修复后的代码,因此我下载了一些以前的版本。
最后,该代码在JDK 1.8.0_202版本中找到:
与上一个屏幕截图的源代码的区别在于,前者有一个额外的旋转字段,可以缓冲方法。
我必须找到这条代码行的原因是要证明这种代码确实出现在某些JDK版本中。
好吧,现在我们看看Waitchget方法在做什么。
首先,当调用get()方法时,如果结果仍然为null,则意味着异步线程执行的结果尚未准备就绪,然后调用WaitchGet方法:
当我们进入Waitchget方法时,我们只注意Bug的两个分支以判断:
首先将旋转的值初始化为-1。
然后,当结果为null时,始终执行while循环。
因此,如果您输入周期,则首次致电可用处理方法。<<8 ,即 256。
然后再次进行循环,走入到 spins>判断0的分支,然后进行随机操作。如果随机出现的值大于或等于0,则旋转将减少。
只有将其简化为0时,它才能输入我被我构成的逻辑:
换句话说,这是为了将旋转从256降低到0,并且由于存在随机函数,因此循环的数量必须大于256次。
但是,还有另一个很大的前提,也就是说,每当周期循环时,都会确定是否仍然建立了周期条件。也就是说,判断结果是否仍然为null。只有无效将继续减少。
那么,您说这个代码正在做什么?
实际上,评论已经很清楚地写了:
在多处理器上使用简短的自旋等待。
简而言之,这是一个四级词汇,您必须记住,您必须参加测试。它的意思是“短”,这是一个不规则的动词,其最高级别是最简短的。
顺便说一句,每个人都应该知道旋转一词。我忘了以前为每个人教这些单词,只是一起聊天,观看小黑板:
因此,注释是:如果它是多处理器,请等待短暂的旋转。
从256到0的过程是这个“简短的自旋等”。
但是,如果您考虑一下,在等待旋转的过程中,首次输入循环时,可用的处理器方法只会调用一次。
那么为什么会消耗性能呢?
是的,它确实只有一次称为get()方法,但是您不会持有get()方法调用更多的地方。
以Dubbo为例。在大多数情况下,每个人的调用方法使用默认同步调用方案。IS,将调用一次可用的处理器方法。
那么解决方案是什么?
我以前已经看过它,只需找到可用处理器方法的返回值即可找到缓存的字段:
但随后是“预言”,此“ proplem”意味着,如果我们慢慢保存多处理器的值,假设程序在运行程序运行过程中从多处理器变为单个处理器,则该值它将被更改。这是不准确的,尽管这是不太可能的变化,但是即使这种“预言”确实发生了,也会导致较小的性能损失。
因此,每个人都看到了这样的代码。这是“我们可以在字段中缓存此值”:
特定的代码更改是:
http://cr.openjdk.java.net/~shade/8227018/webrev.01/src/share/classes/java/java/chautil/completablefuture.java.html
因此,当您去查看源代码的这一部分时,您会发现旋转字段上实际上有一个很长的段落,情况就是这样:
为每个人翻译:
1.在候补方法中,在阻塞操作之前旋转。
2.无需在单个处理器上旋转。
3.调用运行时间的成本。可利用的处理器非常高,因此此值在此处缓存。但是,此值是首次可用的CPU数量。如果系统启动时只有一个CPU可以使用,则可以使用旋转的值将初始化为0。即使更多的CPU在线也不会改变。
当您在上一个错误的描述中有路面时,您会理解为什么在这里写这么大的段落。
有些学生确实浏览了代码,也许您看到的是:
情况是什么?我根本看不到与旋转相关的代码。这不是这个欺骗诚实的人吗?
恐慌,猴子不着急,你还没有完成吗?
我们注视着图片中的这句话:
您只需要在JDK 8中执行此维修,因为JDK 9的代码和更高版本不是这样写的。
例如,在JDK 9中,整个旋转的逻辑被直接删除,因此请勿等待此简短旋转:
http://hg.openjdk.java.net/jdk9/jdk9/jdk9/jdk/rev/f3af17da360b
尽管此短期旋转等待已被删除,但实际上是一个学习操作。
问题:为什么在不引入时间的情况下做出旋转等待效果?
答案是已删除的代码。
但是有人说,当我第一次看到此代码时,我感到很尴尬。这种短旋转能够扩展多长时间?
添加此旋转以在以下逻辑下执行公园代码,这有点重,但是我认为这个“短暂自旋等”的好处实际上是最小的。
因此,我也理解为什么将来将删除整个代码。当删除此代码时,作者没有意识到这里有一个错误。
这里提到的作者实际上是道格·莱(Doug Lea)。
我为什么这么说?
根据此错误链接中提到的错误编号8227018,它们实际上描述了同一件事:
里面有这样的对话,大卫·霍尔姆斯(David Holmes)和道格·利(Doug Lea)出现了:
福尔摩斯提到了“在字段中缓存此值”的解决方案,并获得了道格的同意。
道格说:JDK 9不再使用旋转。
因此,我个人理解道格(Doug)在不知道这个地方有错误的情况下删除了旋转的逻辑。考虑到什么考虑,我想收入确实不大,而代码令人困惑。删除后最好理解。
每个人都熟悉道格·莉亚(Doug Lea)。谁是大卫·霍尔姆斯(David Holmes)?
茶已经结束了“ Java并发编程”的作者之一。
而且,如果您对我上一篇文章印象深刻,那么您会发现Netizens再次发现了“ J.U.C软件包中的Doug Lea”中写的错误。”在本文中,他出现了:
老朋友再次出现,我建议铁汁在公共屏幕上互动。
我说了这么大的段落。核心想法实际上是运行时的高呼叫成本。可利用的程序员,因此不应在完整的future.waitingget方法中经常调用此方法。
但是,为什么可用的过程被称为高,什么是基础,您必须将其取出!
本节,让我向您展示什么是基础。
基础是此错误描述:
https://bugs.openjdk.java.net/browse/jdk-8227006
标题说:在Linux环境中,Runtime.available Processors的执行时间增加了100倍。
增加了100次,必须进行两种不同的版本比较,那么哪个版本是?
在1.8B191之前的JDK版本上,以下示例程序可以实现运行时的呼叫。AvalainProcessors每秒超过400万次。
但是,在JDK Build 1.8B191和所有主要版本和次要版本(包括11)中,它可以实现的最大呼叫数量约为每秒40,000次,并且性能下降了100次。
这导致了alltableFuture.Waitingget的性能问题,该策略在周期中调用Runtime.AvalainProcessor。由于我们的应用程序在异步代码中显示出明显的性能问题,因此Waitchget是我们最初发现该问题的地方。
测试代码是:
根据错误提交器的描述,如果您在64 -bit Linux上使用JDK 1.8B182和1.8B191运行,您会发现差异的近100倍。
至于为什么有100倍的性能差异,一个名叫Fairoz Matte的兄弟说,当问题出现“ Oscontainer :: IS_Containerize()”时,他已经调试并将问题定位。
他还将问题的初始版本编号定位为8U191 B02。此版本之后,代码将遇到此类问题。
带来问题的问题的升级是改善Docker容器检测和资源分配。
因此,如果您的JDK 8是8U191 B02之前的版本,并且系统打电话高,则恭喜您,您有机会踩这台坑。
然后,以下大个子提供了许多基于此问题的解决方案,并讨论了各种解决方案。
在某些解决方案中,听起来很麻烦,需要编写很多代码。
最后,简·简(Jane)的途径仍然选择了相对简单的缓存解决方案来实施。尽管该解决方案也有些缺陷,但出现的可能性非常低且可以接受。
现在我们知道,在没有鸡蛋的知识点之后,让我们看看为什么呼叫超时时间的方法不是问题。
java.util.concurrent.completablefuture#get(long,java.util.concurrent.timeunit)
首先,您可以看到内部调用方法是不同的:
有一个超时get()方法,在内部调用TimeDget方法,并且参数为超时。
单击计时方法以了解为什么呼叫胆管时间的get()方法不是问题:没有问题:
答案是在代码代码中写给您的:我们故意在此处旋转(例如watchget),因为上面的纳米段()呼叫就像旋转。
可以看出,在此方法中,没有呼吁运行时。可利用的处理器,因此没有相应的问题。
现在,我们回到开始:
所以您说,如果我们更改下面的效果?
它必须有所不同。
再一次:Dubbo作为开源中间件可能会以各种不同的JDK版本运行,此方法是其主要链接上的核心代码。对于特定的JDK版本,这种优化确实是为了表现性能改进非常有用。
因此,编写中间件仍然有些有趣。
最后,我将向您发送机会提交Dubbo的源代码。
在下面的课程中:
org.apache.dubbo.rpc.asyncrpcresult
仍然有两种方法:
但是上面的get()方法仅由测试类调用:
您可以将它们完全更改为调用(长时间,TimeUnit单元),然后直接删除GET()方法。
我认为这一定是合并的。
如果您想为开源项目做出贡献并熟悉该过程,那么这是一个很好的机会。