Java JIT编译之父Cliff Click的大型访谈

Cliff Click是Cratus的CTO(用于流程改进的物联网传感器),是多家初创公司(包括Rocket Realtime School,Neuresic和H2O.ai)的创始人和联合创始人,并成功退出了多家公司。 Cliff于15岁(TRS Z-80的Pascal)编写了他的第一个编译器! 最著名的是在Java中开发C2(节点之海,IR)。 该编译器向世界展示了JIT可以生成高质量的代码,这已成为使Java成为主要的现代软件平台之一的因素。 然后,Cliff帮助Azul Systems用纯Java软件构建了一个864核大型机,该软件支持500 GB堆上的GC暂停10毫秒。 通常,Cliff设法在JVM的所有方面工作。

这个喧嚣是对克里夫的一次精彩采访。 我们将讨论以下主题:


  • 过渡到低级优化
  • 如何做很多重构
  • 成本模型
  • 低级优化培训
  • 提高生产力的案例研究
  • 为什么要创建自己的编程语言
  • 绩效工程师职业
  • 技术挑战
  • 关于寄存器分配和多核的一些知识
  • 生活中最大的挑战

采访人:


  • Amazon Web Services的Andrey Satarin 。 在他的职业生涯中,他设法完成了完全不同的项目:在Yandex中测试了分布式NewSQL数据库,在卡巴斯基实验室中测试了云检测系统,在Mail.ru中测试了多用户游戏,并在德意志银行进行了货币兑换计算服务。 他对测试大型后端和分布式系统感兴趣。
  • Netcracker的Vladimir Sitnikov 。 十年来,他一直致力于NetCracker OS的性能和可扩展性,该软件是电信运营商用来自动化网络和网络设备管理流程的软件。 他对Java和Oracle数据库性能问题感兴趣。 作者在官方PostgreSQL JDBC驱动程序中进行了十几项性能改进。

过渡到低级优化


Andrei :您是Java的JIT编译领域的知名人士,并且通常从事性能方面的工作,对吗?


悬崖 :就是这样!


安德鲁 :让我们从有关绩效的一般问题开始。 您如何看待高级优化和低级优化(例如在CPU级别的工作)之间的选择?


悬崖 :很简单。 最快的代码是永远不会运行的代码。 因此,您始终需要从高层次开始,着手研究算法。 除非有一些相当大的常数介入,否则更好的O表示法会胜过更差的O表示法。 低级事物是最新的。 通常,如果您对堆栈的其余部分进行了充分的优化,那么仍然剩下一些有趣的东西-这就是底层。 但是如何从高层次入手呢? 如何找到足够的高水平工作? 好吧...没办法。 没有现成的食谱。 您需要了解问题,决定要做什么(以免将来再采取不必要的步骤),然后才能发现可以说出有用内容的探查器。 在某个时候,您自己了解自己摆脱了不必要的事情,现在是时候对低水平进行微调了。 这绝对是一种特殊的艺术。 许多人会做不必要的事情,但是动作如此之快以至于他们没有时间去关心性能。 但这只要问题没有直截了当。 通常,只有在99%的时间里,没人关心我的工作,直到某个人关心的重要事情没有走上关键的道路。 在这里,每个人都开始谈论“为什么它从一开始就无法完美运行”的话题。 通常,总会有一些性能需要改进。 但是99%的时间您没有潜在客户! 您只是在尝试使某些事情起作用,并且在此过程中您了解了什么是重要的。 您永远不会事先知道这件作品需要做得完美,因此,从本质上讲,您必须在所有方面都做到完美。 这是不可能的,而且您不这样做。 总会有很多事情要解决-这是完全正常的。


如何做很多重构


安德鲁 :您如何提高绩效? 这是一个跨领域的问题。 例如,您是否需要处理大量现有功能交叉产生的问题?


克里夫 :我尽量避免这种情况。 如果我知道性能会成为问题,那么在开始编码之前,尤其是在数据结构上,我应该先考虑一下。 但是通常您会在以后发现所有这些。 然后,您必须采取极端措施,并执行我所说的“重写并征服”:您需要抓住相当大的一块。 由于性能问题或其他原因,仍然必须重写部分代码。 不管重写代码的原因是什么,重写大块比小块几乎总是更好。 这时,每个人都开始恐惧起来:“天哪,你不能触摸太多代码!” 但是,实际上,这种方法几乎总是效果更好。 您需要立即解决这个大问题,在它周围画一个大圆圈,然后说:我将重写圆圈中的所有内容。 边框比其内部需要替换的内容小得多。 而且,如果这样的边界划分可以让您完美地完成内部工作-双手不束缚,那么就可以做自己想做的事情。 一旦了解了问题,重写过程就容易了许多,所以请花大价钱!
同时,当您进行大量重写并了解性能将成为问题时,您可以立即开始担心它。 通常,这会变成一些简单的事情,例如“不要复制数据,尽可能简单地管理数据,使其更小”。 在大型重写中,有一些标准方法可以提高性能。 他们几乎总是围绕数据。


成本模型


安德鲁 :在其中一个播客中,您谈到了生产率方面的成本模型。 您能解释一下这是什么意思吗?


悬崖 :当然可以。 我出生于处理器性能极为重要的时代。 这个时代又回来了-命运并非没有讽刺意味。 我开始生活在八位计算机时代;我的第一台计算机使用256字节。 它是字节。 一切都很小。 我们必须阅读说明,并且一旦我们开始向上移动编程语言堆栈,这些语言就会越来越多地使用。 先是汇编器,然后是Basic,然后是C,然后C接管了许多细节工作,例如寄存器分配和指令选择。 但是那里的一切都非常清楚,如果我创建了一个变量实例的指针,那么我将获得负载,而这条指令的成本是已知的。 Iron产生了已知数量的机器周期,因此可以简单地通过添加要运行的所有指令来计算不同零件的执行速度。 每个比较/测试/分支/调用/装入/存储都可以折叠起来并说:在这里您有提前期。 提高性能后,您一定会注意与小热循环相对应的数字。
但是,一旦您切换到Java,Python和类似的工具,您很快就会摆脱底层的铁杆。 Java中的getter调用费用是多少? 如果正确内联了HotSpot中的JIT,它将被加载,但是如果没有正确地嵌入 ,则将是一个函数调用。 由于挑战在于热循环,因此它将撤消该循环中的所有其他优化。 因此,实际价值将更大。 而且,您立即失去了查看一段代码的能力,并且无法理解我们应该根据处理器时钟速度,使用的内存和缓存来执行它。 仅当您确实沉醉于性能时,所有这些才变得有趣。
现在,我们处在十年来处理器速度几乎没有增长的情况下。 旧时代回来了! 您不再指望良好的单线程性能。 但是,如果您突然从事并行计算-这非常困难,那么每个人都将您视为James Bond。 十倍加速通常发生在有人拍东西的地方。 并发需要很多工作。 为了获得相同的十倍加速,您需要了解成本模型。 它要花多少钱。 为此,您需要了解舌头是如何躺在下面的铁上的。
马丁·汤普森(Martin Thompson)在他的“ 机械同情”博客上说了一个好话 ! 您需要了解铁将要做什么,将如何精确地做铁,以及为什么它通常会做它的工作。 使用此功能,开始阅读说明并找出执行时间流向何方非常简单。 如果您没有接受适当的培训,则只是在黑暗的房间里寻找一只黑猫。 我不断看到人们在优化性能,却不知道自己在做什么。 他们非常受折磨,没有真正去某个地方。 当我使用同一段代码时,在那里放下几个小技巧,并获得5或10倍的加速,它们就是这样的:嗯,这很不诚实,我们已经知道您会更好。 太神奇了 我在说什么...成本模型是关于您编写​​的代码及其在总体上平均运行的速度。


安德鲁 :如何保持这样的音量? 这是通过更多的经验实现的吗? 从哪里获得这种经验?


克里夫 :嗯,我的经历并不是最简单的方法。 我在可以理解每条指令的时候在汇编器中编程。 听起来很傻,但是从那时起,在我的记忆中,Z80指令集就永远存在了。 我不记得谈话后一分钟的名字,但我记得40年前写的代码。 有趣的是,它看起来像是“ 博学的白痴 ”综合症。


低级优化培训


安德鲁 :有没有更简单的经营方式?


悬崖 :是的,不是。 我们所有人使用的熨斗在这段时间内并没有发生太大变化。 除Arm智能手机外,每个人都使用x86。 如果您不进行任何硬核嵌入,那么您将拥有相同的东西。 好吧接下来 指令也已经有好几个世纪没有变化了。 您需要去用汇编器编写一些东西。 有点,但足以开始理解。 您在微笑,但我绝对是认真的。 有必要了解语言和铁的对应关系。 之后,您需要走一点,撒尿,然后为一种小的玩具语言制作一个小的玩具编译器。 “玩具”表示您需要在合理的时间内制作出来。 它可能非常简单,但是必须生成指令。 生成指令的行为将使我们能够理解在每个人都编写的高级代码与在硬件上运行的机器代码之间的桥梁的成本模型。 在编写编译器时,这种对应关系将在大脑中燃烧。 即使是最简单的编译器。 在那之后,您可以开始研究Java以及它存在更深的语义鸿沟的事实,并且在Java之上建立桥梁要困难得多。 在Java中,很难理解我们的桥梁是好是坏,这将使其分崩离析。 但是,当您查看代码并理解时,需要一些起点:“是的,此getter必须每次都内联”。 然后事实证明,有时会发生这种情况,但情况例外,当方法变得太大而JIT开始内联所有内容时。 这样的地方的表现可以立即预测。 通常,getter可以很好地工作,但是随后您看到了巨大的热循环,并意识到有些函数调用不知道它们在做什么。 这是吸气剂被广泛使用的问题,它们不内联的原因-尚不清楚这是否是吸气剂。 如果您有一个超小的代码库,则可以记住它,然后说:这是一个吸气剂,但这是一个塞特器。 在大型代码库中,每个函数都有自己的故事,通常这是任何人都不知道的。 探查器说,我们在某种周期上损失了24%的时间,要了解该周期的作用,我们需要查看内部的每个函数。 不学习功能就不可能理解它,并且这严重地减慢了理解过程。 这就是为什么我不使用getter和setter的原因,我迈上了一个新台阶!
从哪里获得成本模型? 好吧,你当然可以阅读一些东西……但是我认为最好的方法就是行动。 制作一个小的编译器,这将是实现成本模型并将其安装在自己脑海中的最佳方法。 一个适合微波编程的小型编译器是初学者的任务。 好吧,我的意思是,如果您已经具备编程技能,那么他们就足够了。 所有这些事情都像解析字符串一样,您将拥有某种代数表达式,以正确的顺序从那里提取数学运算的指令,从寄存器中获取正确的值-所有这些都一次完成。 尽管您会做到这一点,但它会烙印在大脑中。 我想每个人都知道编译器会做什么。 这将使您对成本模型有所了解。


提高生产力的案例研究


安德鲁 :在演奏方面还有什么需要注意的?


悬崖 :数据结构。 顺便说一句,是的,我很久没有教这些课程了…… Rocket School 。 这很有趣,但是花了很多精力进行投资,我也有生命! 知道了 因此,在其中一个有趣的大型课程中,“您的性能如何提高”,我举了一个例子:从CSV文件读取了两个半GB的fintech数据,然后我们必须计算出售的产品数量。 定期报价市场数据。 自70年代以来,UDP数据包已转换为文本格式。 芝加哥商品交易所有各种各样的东西,例如黄油,玉米,大豆等。 有必要计算这些产品,交易次数,资金和货物的平均流动量等。 这是一个非常简单的交易数学:找到产品代码(哈希表中有1-2个字符),获取金额,将其添加到一组交易中,增加交易量,增加价值,以及其他一些事情。 很简单的数学。 玩具的实现非常简单:所有内容都位于文件中,我读取文件并在文件中四处移动,将各个条目分离为Java字符串,在其中寻找必要的内容,然后根据上述数学将其折叠。 它以低速运行。


通过这种方法,一切显而易见,正在发生的事情,而并行计算将无济于事,对吧? 事实证明,只有选择正确的数据结构,生产率才能提高五倍。 这甚至使经验丰富的程序员感到惊讶! 在我的特定情况下,诀窍是您不应在热循环中进行内存分配。 好吧,这不是全部事实,但总的来说-当X足够大时,您不应突出显示“ X一次”。 当X为2个半GB时,您不应“每封信一次”,“每行一次”或“每字段一次”分配任何东西。 那正是需要时间的地方。 它甚至如何工作? 想象一下调用String.split()BufferedReader.readLine()Readline通过网络中的一组字节组成一行,每行一次,每行数亿行。 我接受这条线,解析然后扔掉。 为什么要扔掉它-好,我已经处理了,仅此而已。 因此,对于从这2.7G读取的每个字节,将在该行中写入两个字符,即已经写入5.4G,并且我不再需要它们,因此将其丢弃。 如果您查看内存带宽,我们将加载2.7G,该内存将通过内存和处理器中的内存总线,然后将两倍的内存发送到位于内存中的线路,并且每创建一条新线路,所有这些都会磨损。 但是我需要读它,熨斗才能读它,即使那样一切都会被磨擦。 我必须写下来,因为我创建了该行并且缓存已满-缓存无法容纳2.7G。 总的来说,对于每个读取的字节,我又读取两个字节,再写入两个额外的字节,结果它们的比率为4:1-在这个比率中,我们浪费了内存带宽。 然后事实证明,如果我执行String.split() ,那么我不是最后一次这样做,那么里面可能还有6-7个字段。 因此,传统的CSV读取代码加上行解析会导致内存带宽损失,相对于您真正想要的带宽为14:1。 如果扔掉这些分泌物,则可以加速五倍。


而且不是那么困难。 如果您从正确的角度看待代码,那么一旦意识到问题的实质,一切都将变得非常简单。 甚至根本不要停止分配内存:唯一的问题是您分配了一些内容,它立即死亡,并在此过程中烧掉了重要的资源,在这种情况下,这就是内存带宽。 所有这些都会导致生产率下降。 在x86上,您通常需要主动消耗处理器时钟,而在这里您要更早地消耗所有内存。 解决方案-您需要减少排放量。
问题的另一部分是,如果在内存条结束时就启动分析器,就在这种情况发生的那一刻,您通常会等待高速缓存返回,因为它充满了所有这些行所产生的垃圾。 因此,每次加载或存储操作都会变慢,因为它们会导致高速缓存中的未命中-整个高速缓存变得很慢,等待垃圾将其丢弃。 因此,探查器将仅显示在整个周期中涂抹的热随机噪声-代码中将没有单独的热指令或位置。 只是噪音。 而且,如果您查看GC周期,它们将都是年轻一代且超快-最多微秒或毫秒。 毕竟,所有这些记忆会立即死亡。 您分配了数十亿兆字节,然后将其削减,再削减,再削减一次。 这一切很快发生。 事实证明,存在廉价的GC周期,整个周期都有温暖的噪音,但我们希望获得5倍的加速度。 那一刻,我的脑海中应该响起一些声音:“为什么呢?!” 带宽溢出没有出现在经典调试器中,您需要运行硬件性能计数器调试器并亲自查看。 而不是直接地,可以怀疑这三个症状。 第三个症状是,当您查看突出显示的内容时,询问探查器,他回答:“您制作了十亿行,但是GC是免费的。” 一旦发生这种情况,您就会意识到自己产生了太多的对象并烧毁了整个内存条。 有一种方法可以解决这个问题,但这并不明显。


问题在于数据结构:发生的所有事情背后的裸露结构,它太大,在磁盘上为2.7G,因此非常不希望复制该文件-我想立即将其从网络字节缓冲区加载到寄存器中,以免对字符串进行读写来回五次。 不幸的是,默认情况下,Java不会将此类库作为JDK的一部分提供给您。 但这是微不足道的,对吧? 实际上,这些代码是5至10行,将用于实现您自己的缓冲的行加载器,该行加载器重复行类的行为,同时充当基础字节缓冲区的包装器。 结果,您几乎就像在使用字符串一样工作,但是实际上有指向缓冲区的指针移动,并且原始字节没有被复制到任何地方,这样,相同的缓冲区会不时地被重用,并且操作系统很乐意继续使用它想要的事情,例如这些字节缓冲区的隐藏双缓冲,您自己就不再需要无休止的不必要数据流。 顺便说一句,您了解在使用GC时,是否可以确保在最后一个GC周期之后处理器不会看到每个内存分配? 因此,所有这些内容都无法存储在高速缓存中,然后发生100%保证的未命中。 在x86上使用指针时,从内存中减去寄存器需要1-2个周期,一旦发生这种情况,您就需要付费,付费,付费,因为内存全部位于NINE缓存中 -这就是分配内存的成本。 现值。


换句话说,数据结构最难更改。 而且,一旦您意识到选择了错误的数据结构会损害将来的生产力,通常就需要加快基本工作的速度,但是如果不这样做,情况将会更糟。 首先,您需要考虑数据结构,这很重要。 这里的主要成本在于粗体数据结构,它们开始以“我将数据结构X复制到数据结构Y,因为我更喜欢形状”的样式开始使用。 但是复制操作(似乎很便宜)实际上花费了一条内存,并且所有丢失的运行时都被掩埋了。 如果我有一个带有JSON的巨型字符串,并且想要将其从POJO或类似的东西转换成结构化的DOM树,则解析此字符串并构建POJO,然后在将来再次调用POJO的操作将变得毫无价值-这不是一件昂贵的事情。 除了您在POJO上运行的频率要比在线运行的频率高得多。 取而代之,您可以尝试解密该字符串并仅从中提取所需的字符串,而不将其转换为任何POJO。 如果所有这一切都发生在要求最高性能的路径上,那么您就不需要POJO了-您需要以某种方式直接深入研究。


为什么要创建自己的编程语言


安德烈 :您说过,要了解成本模型,您需要编写自己的小语言……


克里夫 :不是语言,而是编译器。 语言和编译器是两回事。 最重要的区别是在你的头上。


Andrei :据我所知,您正在尝试创建自己的语言。 怎么了


悬崖 :因为我可以! 我已经退休了一半,所以这是我的爱好。 我一生都在使用别人的语言。 我还致力于编码风格。 也因为我看到其他语言的问题。 我看到有更好的方法来做平常的事情。 我会用它们。 我只是厌倦了自己,Java,Python,任何其他语言中的问题。 我在业余爱好上写React Native,JavaScript和Elm,这与退休无关,而与积极工作有关。 而且我也用Python编写,很可能会继续从事Java后端的机器学习。 有许多流行的语言,并且它们都有有趣的功能。 每个人都擅长自己的东西,您可以尝试将所有这些芯片整合在一起。 因此,我研究了我感兴趣的事物,语言的行为,并尝试提出合理的语义。 到目前为止,我正在这样做! 目前,我在内存的语义方面苦苦挣扎,因为我想同时在C和Java中使用它,并为加载和存储获得强大的内存模型和内存语义。 同时,像Haskell中一样具有自动类型推断。 在这里,我试图将类似Haskell的类型推断与在C和Java中都可以工作的内存混合在一起。 例如,最近2-3个月我一直在这样做。


安德烈(Andrei) :如果您正在构建一种语言,该语言可以从其他语言中获得更好的表现,那么您是否认为有人会做相反的事情:采纳您的想法并加以利用?


悬崖 :那就是新语言的出现! 为什么Java与C类似? 因为C具有所有人都理解的良好语法,并且Java受到此语法的启发,所以增加了类型安全性,检查了数组的边界,GC,并且他们改进了C的某些功能。 但是他们受到了很多启发,对吧? 每个人都站在您面前的巨人的肩膀上-这就是取得进步的方式。


安德鲁 :据我了解,您的语言在内存使用方面将是安全的。 您是否曾经考虑过实现Rust的借入检查器之类的功能? 你看着他,他觉得你怎么样?


Cliff :好吧,我多年来一直在写C语言,其中包含所有这些malloc和free,并且我手动管理生命周期。 您知道,90-95%的手动管理生命周期具有相同的结构。 手动执行此操作非常非常痛苦。 我希望编译器简单地说出那里发生的事情以及您通过操作实现的结果。 对于某些事情,借用检查器可以直接使用。 他应该自动显示信息,了解所有内容,甚至不给我加重负担,以表达这种理解。 他至少应该进行本地转义分析,并且只有在他没有成功时,才需要添加描述生命周期的类型注释-这种方案比借用检查器或任何现有的内存检查器要复杂得多。 在“一切都按顺序进行”和“我什么都不懂”之间进行选择-不,必须有更好的选择。
因此,作为编写大量C代码的人,我认为拥有自动生命周期控制的支持是最重要的。 我已经厌倦了Java使用多少内存,而主要的抱怨是在GC中。 使用Java分配内存时,您将不会返回上一个GC循环中本地的内存。 在具有更精确的内存管理的语言中,事实并非如此。 如果调用malloc,则立即获得通常使用的内存。 通常,您会用记忆做一些暂时的事情,然后立即将其恢复。 然后她立即返回到malloc池,下一个malloc周期再次将她拉出。 因此,在特定的时间点,实际的内存使用减少为一组活动对象,外加泄漏。 如果一切都不以您不雅的方式进行,那么大部分内存都将存放在缓存和处理器中,并且可以快速运行。 但是,这需要使用malloc和free进行大量手动内存管理,并在正确的位置按正确的顺序进行调用。 Rust本身可以正确处理此问题,并且在很多情况下,Rust可以提供更高的性能,因为内存消耗仅缩小到当前计算范围,而不是等待下一个GC周期释放内存。 结果,我们获得了一种非常有趣的方法来提高性能。 而且功能非常强大-从某种意义上说,我在为金融科技处理数据时就做了这样的事情,这使我获得了五倍的加速。 这是一个相当大的加速,尤其是在处理器没有变得越来越快的世界中,我们大家都在继续等待改进。


绩效工程师职业


安德鲁 :我也想问一下整个职业。 您因在HotSpot的JIT工作,然后移居至Azul而闻名,这也是JVM公司。 但是他们已经从事的工作比软件更多。 然后突然转向大数据和机器学习,然后转向欺诈检测。 怎么发生的? 这些是非常不同的发展领域。


克里夫 :我已经编程了一段时间了,并且设法在非常不同的班级上报到。 当人们说:“哦,您是为Java编写JIT的人!”时,总是很有趣。 但是在此之前,我从事过PostScript克隆-Apple曾经将其用于激光打印机的语言。 在此之前,他完成了Forth语言的实现。 我认为对我来说,共同的主题是工具的开发。 我一生都在开发其他人用来编写酷程序的工具。 但是我也参与了操作系统,驱动程序,内核级调试器,用于开发OS的语言的开发,这些开发虽然很简单,但是随着时间的流逝,一切变得越来越复杂。 但是,主要的话题仍然是工具的开发。 Azul和Sun之间生活了很大一部分,这与Java有关。 但是,当我开始大数据和机器学习时,我再次戴上帽子,说:“哦,现在我们遇到了一个不重要的问题,这里发生了很多有趣的事情和做某事的人”。 这是一条值得走的伟大发展道路。


是的,我真的很喜欢分布式计算。 我的第一份工作是在C上做广告项目的学生。 这些是在Zilog Z80芯片上进行分布式计算的,该芯片收集了由真实模拟分析仪产生的用于模拟光学文本识别的数据。 这是一个很酷而且完全不正常的话题。 但是存在问题,某些部分未被正确识别,因此有必要获取一张照片并将其显示给一个已经用眼睛看过并告知那里所说的话的人,因此存在数据变戏法者,并且这些工作有其自己的语言。 有一个后端可以处理所有这些问题-与运行vt100终端的Z80并行运行-每个人一个,并且Z80上存在并行编程模型。 星型配置中所有Z80共享的某个公用内存; 背板是共享的,一半的RAM是在网络内共享的,另一半是私有的或用于其他用途。 具有共享的...半共享内存的有意义的复杂并行分布式系统。 那时……已经不记得了,大约在80年代中期。 很久以前。
是的,我们假设30年是很长的时间,与分布式计算相关的任务已经存在了很长时间,人们一直在与Beowulf集群作战。 这样的集群看起来像...例如:有以太网,并且您的快速x86已连接到该以太网,现在您想要获取伪造的共享内存,因为没有人可以处理分布式计算的编码,它太复杂了,因此是伪造的带有保护功能的共享内存x86内存页面,如果您写到此页面,我们告诉其他处理器,如果其他处理器能够访问相同的共享内存,则需要从您那里下载该内存,因此出现了诸如缓存一致性支持协议之类的信息和软件。 有趣的概念。 当然,真正的问题是不同的。 所有这些工作正常,但是您很快就遇到了性能问题,因为没有人足够了解性能模型-那里有什么内存访问模式,如何确保节点不会无穷无尽地相互ping通,等等。


在H2O中,我想到了这一点:开发人员自己负责确定隐藏在何处的并行性,而不是隐藏在何处。 我想出了一种编码模型,编写高性能代码非常容易。 但是编写运行缓慢的代码很困难,看起来很糟糕。 您需要认真尝试编写慢速代码,必须使用非标准方法。 制动代码一目了然。 因此,通常编写的代码可以快速运行,但是您必须弄清楚在共享内存的情况下该怎么做。 所有这些都与大型数组有关,并且其行为类似于并行Java中的非易失性大型数组。 我的意思是,假设有两个线程写入并行数组,其中一个赢了,另一个分别输了,而您不知道哪个是谁。 如果它们不是易变的,那么顺序可以是任何东西-确实很好。 人们真的很在乎操作的顺序,他们正确设置了volatile,并且他们期望在正确的地方出现内存问题。 否则,他们将简单地以从1到N的循环形式编写代码,其中N约为数万亿,希望所有复杂的情况都将自动变为并行状态-并不能在那里工作。 但是在H2O中,它既不是Java也不是Scala,如果需要,您可以将其视为“ Java minus minus”。 这是一种非常容易理解的编程风格,类似于编写带有循环和数组的简单C或Java代码。 但是同时,内存可以以TB为单位进行处理。 我仍然使用H2O。 – , . Big Data , H2O.



: ?


: ? , – .
. . , , , , . Sun, , , , . , , . , C1, , – . , . , x86- , , 5-10 , 50 .


, , , , C. , , - , C . C, C . , , C, - … , . , . , , . , , 5% . - – , « », , . : , , . . , – , . , . - – . , , ( , ), , , . , , , .


, , , , , , . , , , - . , , , . , , , , . , : , . , , - : , , - , . – , , – ! – , . Java. Java , , , , – , « ». , , . , Java C . – Java, C , , , . , – , . , . , , . : .



: - . , , - , ?


: ! – , NP- - . , ? . , Ahead of Time – . - . , , – , ! – , . , , . . ? , : , , - ! - , . . , , . : - , - . , , . , , , , - . ! , , , – . . NP- .


: , – . , , , , …


: . «». . , . – , , , ( , ). , - . , , , . , , . , . , , . , , . , , - , – . – . , GC, , , , – , . , . , , . , – , ? , .


: , ? ?


: GPU , !


: . ?


: , - Azul. , . . H2O , . , GPU. ? , Azul, : – .



: ?


: , … . , . , , , , . , , . , Java C1 C2 – . , Java – . , , – . … . - , Sun, … , , . , . , . … … , . , , . . - , : . , , , , , , . , . . , . « , , ». : «!». , , , : , .


– , , , . . , , , , . , Java JIT, C2. , – . , – ! . , , , , , , . . . , . , , , , : , , . , – . , , - . : « ?». , . , , : , , – ? , . , , , , , , - .


: , -. ?


: , , . – . . , . . . : , , - – . . , , – , . , , , , - , . , . , , - . , , – , .
, . , – , , . , . , – . , . , , « », , – , , , , . , , « ».


. . - , , «»: , – . – . , , . «, -, , ». , : , . , , . . – , . , ? , ? ? , ? . , . – . . , . – – , . , « » . : «--», : «, !» . . , , , , . , . , . , – , . – , . , , , .


, – , . , , . , . , , , , . , , . , , , , . . , , , . , , , , . , , , . , – , , , . , .


: … . , . . Hydra!


Hydra 2019, 11-12 2019 -. «The Azul Hardware Transactional Memory experience» . .

Source: https://habr.com/ru/post/zh-CN458718/


All Articles