【问题标题】:Why is Go so slow (compared to Java)?为什么 Go 这么慢(与 Java 相比)?
【发布时间】:2011-02-11 20:42:15
【问题描述】:

正如我们在 2010 年从 The Computer Language Benchmarks Game 看到的那样:

  • Go 平均比 C 慢 10 倍
  • Go 比 Java 慢 3 倍!?

记住 Go 编译器会生成用于执行的本机代码,这怎么可能?
Go 的不成熟编译器?还是 Go 语言存在一些内在问题?

编辑:
大多数答案否认 Go 语言的内在缓慢,声称问题出在不成熟的编译器中。
因此,我做了一些自己的测试to calculate Fibonacci numbers:迭代算法在 Go (freebsd,6g) 中运行,same 速度与 C 中一样(使用 O3 选项)。枯燥的递归在 Go 2 times 中运行比在 C 中慢(使用 -O3 选项;使用 -O0 - 相同)。但我还没有看到像基准游戏中那样下降 10 倍。

【问题讨论】:

  • 公平地说,C 是伪装的 ASM,而 Java 近来在底层进行了一些重要的优化。
  • 也许基准测试也不能反映 Go 的优势。可能其他基准测试实际上比这更快。此外,通常最重要的不是性能,而是代码的可读性。
  • @extraneon:我同意。请记住,Go 是为 Google 设计的,Google 通常会在 2 百万 个内核上运行代码。我相信 Benchmarks Game 只使用了 4 个内核。
  • @extraneon:我总体上同意,但 Go 在设计时特别考虑了速度,例如,“生成的程序运行速度几乎与可比较的 C 或 C++ 代码一样快。”
  • 您的问题假设太多:“大多数答案否认 Go 语言的内在缓慢”是在问题中使用的错误短语。你有问题要问,或者要发表声明吗?请参阅c2.com/cgi/wiki?HostileStudent 以了解您的错误。

标签: java performance go benchmarking


【解决方案1】:

6g 和 8g 编译器并没有特别优化,因此它们生成的代码并不是特别快。

它们的设计目的是让自己快速运行并生成正常的代码(有一些优化)。 gccgo 使用 GCC 现有的优化通道,可能会提供与 C 的更有意义的比较,但 gccgo 的功能还不完整。

基准数据几乎完全与实施质量有关。它们与语言本身并没有太大的关系,除非实现花费运行时支持基准并不真正需要的语言特性。在大多数编译语言中,一个足够聪明的编译器理论上可以剔除不需要的东西,但是有一点你正在操纵演示,因为很少有真正的语言用户会编写不使用该功能的程序.将事物移开而不完全移除它们(例如,在 JIT 编译的 Java 中预测虚拟调用目标)开始变得棘手。

FWIW,当我查看它时,我自己对 Go 进行的非常简单的测试(基本上是整数加法循环),gccgo 生成的代码接近 gcc -O0gcc -O2 之间范围的快速端,相当于C. Go 本身并不慢,但编译器还没有做所有事情。对于 10 分钟前的语言来说,这不足为奇。

【讨论】:

  • 此外,计算机语言基准游戏中的围棋程序可能没有像 C 和 Java 那样优化。
  • gcc -O0 和 gcc -O3 之间呢?甚至有编译器会“做所有事情”的意图吗?
  • @igouy:嗯,我很确定 gccgo 会进行垃圾收集,但目前它没有。 g 编译器还有一些功能需要使用,例如它们目前并没有特别好地使用主机线程(具体来说,goroutine 调度程序不是抢先式的)。除此之外,我不知道谷歌的计划,g 编译器是否会进行激烈的优化,或者只有 gccgo 会。
  • @xitrium:我认为 Go 的意图是不应该要求实现协同调度,如果他们愿意,他们可以先发制人。参见例如code.google.com/p/go/issues/detail?id=543,它还没有被关闭,因为“荒谬,修复这个所谓的错误会与 Go 语言定义相矛盾”,如果 Go 实现被禁止抢先应该是这样 :-) 问题是更复杂的是,无论有多少 goroutine 可以运行,默认情况下 Go 只使用一个主机线程。
  • 现在的答案可能有点过时了。最近,Go 1.1 的第一个 beta 版本是released,他们表示编译程序的性能提高了大约 30% 到 40%。请有人再做这些测试。
【解决方案2】:

Go FAQ 的下一个版本中,应该会出现类似于以下内容的内容。

性能

为什么 Go 在基准测试中表现不佳 X?

Go 的设计目标之一是 接近 C 的性能 类似的程序,但在一些 基准测试它做得很差, 包括测试/工作台中的几个。这 最慢的依赖于哪些库 可比性能的版本是 在 Go 中不可用。例如, pidigits 取决于多精度 math 包和 C 版本, 与 Go 不同,使用 GMP(编写 在优化的汇编程序中)。基准 依赖于正则表达式 (例如,regex-dna)是 本质上比较了 Go 的权宜之计 正则表达式包成熟,高度 优化的正则表达式库 像 PCRE。

基准游戏赢得广泛 调优和大多数的 Go 版本 基准需要注意。如果你 衡量可比较的 C 和 Go 程序 (反向补码就是一个例子), 你会看到这两种语言很多 原始性能比这更接近 套件会指示。

不过,还有改进的余地。 编译器很好,但可能是 更好,许多图书馆需要专业 表演工作和垃圾 收集器还不够快(甚至 如果是的话,注意不要 产生不必要的垃圾可以有 巨大的影响)。

这里有更多关于 The Computer Benchmarks Game 的详细信息,来自最近的邮件列表线程。

Garbage collection and performance in gccgo (1)

Garbage collection and performance in gccgo (2)

请务必注意,Computer Benchmarks Game 只是一个游戏。在性能测量和容量规划方面有经验的人会仔细匹配现实和实际的工作负载;他们不玩游戏。

【讨论】:

  • 这里有一些来自您已排除的同一线程的详细信息 - groups.google.com/group/golang-nuts/msg/2e568d2888970308
  • 重要的是要注意“基准是一个缸” - 不仅仅是作为基准游戏发布的基准 - shootout.alioth.debian.org/flawed-benchmarks.php
  • (和大家...)当然这是一个“游戏”,但是当我看到围棋比最快的慢两倍在这些基准测试中,我的第一印象是“哇,Go 似乎很快”,因为我知道这些基准测试存在缺陷。相反,当我看到 Ruby 比最快的要慢 65 倍时,我想“不会将 Ruby 用于我的下一个并发数值密集型工作”。所以这可能是一场“游戏”,但如果你对它持保留态度,那么它就有一些道理。
  • 容量规划有一个非常重要的方面:成本。无论您最终需要 X 盒还是 2*X,都会产生巨大的影响。而且由于没有人可以估计未来将在这些设备上运行什么,因此最好的办法是查看不同的工作负载。我已经检查了这些的一些实现,发现它们大部分都可以。我认为结果可以作为估计的基础。
  • 通常,现实世界的系统受 IO 而非 CPU 的约束。因此,Go 是 2x 还是 5x 慢,对容量规划的影响几乎没有故障转移、负载平衡、缓存、数据库拓扑等方面的影响。这就是 YouTube 规模的应用能够负担得起在 Python 中运行许多系统的原因。
【解决方案3】:

我的回答不像其他人那样技术性很强,但我认为它仍然具有相关性。 当我决定开始学习围棋时,我在计算机基准游戏中看到了相同的基准。但老实说,我认为所有这些综合基准对于决定 Go 是否足够快对你来说毫无意义。

我最近使用 Tornado+TornadIO+ZMQ 用 Python 编写了一个消息服务器,对于我的第一个 Go 项目,我决定用 Go 重写服务器。到目前为止,已经使服务器具有与 Python 版本相同的功能,我的测试显示 Go 程序的速度提高了大约 4.7 倍。请注意,我只用 Go 编码可能一周,而我用 Python 编码已经超过 5 年了。

随着他们继续努力,Go 只会变得更快,我认为这实际上取决于它在现实世界应用程序中的表现,而不是微小的计算基准。对我来说,Go 显然产生了一个比我用 Python 生成的程序更高效的程序。这就是我对这个问题的回答。

【讨论】:

  • 你认为你编写 Go 代码会比 Python 慢多少?
  • @AdamSmith - 我会说我编写 Go 代码的速度会比 Python 慢,只是因为我已经编写了 7 年以上的 Python 代码,而且只有一点 Go。但就 Go 与其他静态类型的编译语言而言,我敢打赌我会比其他人更快地编写 Go。就个人而言,我觉得它最接近 Python 的简单性,速度介于 C 和 C++ 之间
  • 我也有类似的故事。我刚开始学习围棋,根据 Benchmarks Game,围棋比 JavaScript V8 慢。事实证明,我的二进制操作密集型程序在未优化的 Go 代码中运行速度比在高度优化的 V8 VM 中快 10 倍。在许多操作中,Go 可能比 C 慢,但是没有人用 C 编写网站。Go 已经是一个完全可行的选择,而且随着新库、框架和工具的出现,它只会变得更好。
  • @user962247 这是一个疯狂而虚假的一揽子声明。我已经写 Go 多年了,而且速度非常快。没有人声称它会在所有可能的综合基准测试中击败 C/C++/Java。但它在某些方面胜出(参见基准游戏网站)。从一个实际上已经编写生产 Go 代码多年的人那里得到它。它既快速又高效。
【解决方案4】:

情况发生了变化。

我认为当前对您问题的正确答案是对“走很慢”的观点提出质疑。在您询问时,您的判断是合理的,但从那以后,go 在性能方面取得了很大进展。现在,它仍然不如 C 快,但从一般意义上讲,速度远不及慢 10 倍。

Computer language benchmarks game

在撰写本文时:

source  secs    KB      gz      cpu     cpu load

reverse-complement
1.167x
Go      0.49    88,320  1278    0.84    30% 28% 98% 34%
C gcc   0.42    145,900 812     0.57    0% 26% 20% 100%

pidigits
1.21x
Go      2.10    8,084   603 2.10    0% 100% 1% 1%
C gcc   1.73    1,992   448 1.73    1% 100% 1% 0%

fasta
1.45x
Go      1.97    3,456   1344    5.76    76% 71% 74% 73%
C gcc   1.36    2,800   1993    5.26    96% 97% 100% 97%

regex-dna
1.64x
Go      3.89    369,380 1229    8.29    43% 53% 61% 82%
C gcc   2.43    339,000 2579    5.68    46% 70% 51% 72%

fannkuch-redux
1.72x
Go      15.59   952 900 62.08   100% 100% 100% 100%
C gcc   9.07    1,576   910 35.43   100% 99% 98% 94%

spectral-norm
2x
Go      3.96    2,412   548 15.73   99% 99% 100% 99%
C gcc   1.98    1,776   1139    7.87    99% 99% 100% 99%

n-body
2.27x
Go      21.73   952 1310    21.73   0% 100% 1% 2%
C gcc   9.56    1,000   1490    9.56    1% 100% 1% 1%

k-nucleotide
2.40x
Go      15.48   149,276 1582    54.68   88% 97% 90% 79%
C gcc   6.46    130,076 1500    17.06   51% 37% 89% 88%

mandelbrot
3.19x
Go      5.68    30,756  894 22.56   100% 100% 99% 99%
C gcc   1.78    29,792  911 7.03    100% 99% 99% 98%

不过,它确实在二叉树基准测试中遭受了残酷的影响:

binary-trees
12.16x
Go      39.88   361,208 688 152.12  96% 95% 96% 96%
C gcc   3.28    156,780 906 10.12   91% 77% 59% 83%

【讨论】:

  • 它现在与 Java 相当,但 Go 不是明确创建为比 Java 更快,同时用于相同的事情(服务器端网络应用程序)?
  • @MaxB 不,它不是为了比 Java 更快而创建的。创建它的目标是具有良好的性能、比 C++ 更快的编译速度以及更容易和本机的并发性,从而使开发人员能够提高工作效率。超越其他语言的运行速度并不是驱动因素。
【解决方案5】:

尽管 Go 的 CPU 周期使用效率不太好,但 Go 并发模型比 Java 中的线程模型快得多,并且可以与 C++ 线程模型相媲美。

请注意,在 thread-ring benchmark 中,Go 比 Java 快 16 倍。在相同的场景中,Go CSP 几乎可以与 C++ 媲美,但使用的内存要少 4 倍。

Go 语言的强大之处在于其并发模型,即通信顺序进程 (CSP),由 Tony Hoare 在 70 年代指定,易于实现且适合高并发需求。

【讨论】:

    【解决方案6】:

    Java 比 Go 和 C++ 快,并且在很多情况下比 C 快,有两个基本原因:

    1) JIT 编译器。它可以基于运行时配置文件通过多个级别内联虚拟函数调用,甚至使用 OO 类。这在静态编译的语言中是不可能的(尽管基于记录的配置文件的较新的重新编译会有所帮助)。这对于大多数涉及重复算法的基准非常重要。

    2) GC。与 malloc 相比,基于 GC 的内存分配几乎是免费的。并且“免费”惩罚可以在整个运行时分摊 - 通常被跳过,因为程序在需要收集所有垃圾之前终止。

    有数百(数千?)非常有才华的开发人员使 GC/JVM 高效。认为您可以“比所有人都更好地编码”是愚蠢的。这本质上是一个人类的自我问题 - 人类很难接受通过有才华的人的适当培训,计算机将比编程它的人类表现得更好。

    顺便说一句,如果你不使用 OO 特性,C++ 可以和 C 一样快,但是你非常接近于刚开始用 C 编程。

    最重要的是,这些测试中的“速度差异”通常毫无意义。 IO 成本比性能差异高出几个数量级,因此将 IO 成本最小化的适当设计总是获胜——即使是在解释语言中也是如此。很少有系统受 CPU 限制。

    最后,人们将“计算机语言基准测试游戏”称为“科学衡量标准”。这些测试完全有缺陷,例如,如果您查看 nbody 的 Java 测试。当我在相同的操作系统/硬件上运行测试时,Java 大约需要 7.6 秒,C 大约需要 4.7 秒——这是合理的——而不是测试报告的 4 倍慢。它是点击诱饵、虚假新闻,旨在产生网站流量。

    最后,最后一点...我使用 Go 运行测试,它是 7.9 秒。当您单击 Go 时,它会将其与 Java 进行比较,而当您单击 Java 时将其与 C 进行比较,这对任何认真的工程师来说都是一个危险信号。

    有关 Java、Go 和 C++ 的真实世界比较,请参阅https://www.biorxiv.org/content/10.1101/558056v1 剧透警告,Java 在原始性能方面名列前茅,Go 在内存使用和挂墙时间方面名列前茅。

    【讨论】:

    • 错误。 C++ 与 C 一样快,尤其是当您使用 OOP 时,这就是他的出生证明。更多的抽象(如在类中),没有任何运行时性能下降,零额外字节内存。如果你不知道,继续玩 java、c#、go、python 等等
    • //顺便说一句,如果你不使用 OO 特性,C++ 可以和 C 一样快 // 但是你非常接近于在 C 中编程 // 开始。如果您这么说,那么您对 ​​c++ 知之甚少,为了您自己,请不要使用它。 c 和 c++ 讨厌魔法和中世纪的思想,本质上是迷信的,就像哦,我听说了,在互联网上阅读它,它一定是真的......远离 c 和 c++,他们会回你我的朋友(诚实的建议)
    • c 是 c++ 的祖先。许多人仍在使用它... c++ 是更好的 c,您可以在不付出代价的情况下做更多事情。 java、c# 和 go 的作者没有得到它,当然,他们得到了,但是他们能做些什么呢?!?与现有(c)代码兼容也是如此。现实生活中的 C 代码海洋! python 是一个不错的玩具,享受吧,我希望他们做对了,但是不,python 的禅宗应该从“编译器是你的朋友”开始......
    • >>显示 Java 程序的 CPU 利用率为 30%
    • @igouy 我承认这可能是我犯的一个错误 - 当我看到负载时,我正在解释“系统负载”术语,并假设用户/系统/io/idle - 我的错误,这是一个实质性的。
    【解决方案7】:

    我认为一个经常被忽视的事实是,JIT 编译可以是 > 静态编译,尤其是对于(运行时)后期绑定的函数或方法。热点 JIT 在 RUNTIME 决定内联哪些方法,它甚至可以根据当前运行的 CPU 的缓存大小/架构调整数据布局。 C/C++ 通常可以通过直接访问硬件来弥补(总体上仍然会表现得更好)。与 C 相比,Go 看起来可能有所不同,因为它的级别更高,但目前缺少运行时优化系统/编译器。 我的直觉告诉我,Go 可能比 Java 更快,因为 Go 不会强制执行那么多指针追逐,并鼓励更好的数据结构局部性 + 需要更少的分配。

    【讨论】:

      【解决方案8】:

      事实上,Go 不仅在设计时优雅高效,而且在运行时也非常高效。关键是使用正确的操作系统,即 LINUX。 Windows 和 Mac OS 下的性能分析结果,因为没有更好的词,要差一两个数量级。

      【讨论】:

        【解决方案9】:

        在linux下,go运行时超级快,完全可以和c/c++媲美。 windows下的go运行时和unix不是一个档次的

        与 java 的比较不是那么重要,go 既适用于系统开发,也适用于应用程序开发(因为 java 更像是只适用于应用程序开发的蓝领)。细节就不说了,但是当像kubernetes这样的东西用go写的时候,你就会发现这不是一个企业顾问友好的玩具

        我不记得谷歌曾经提到过你提到的妥协。 go 是很好的设计,简单,优雅,高效,用于设计系统和应用程序级程序,具有指针,高效的内存分配和释放,避免因易于误用的实现继承而引起的复杂性,为您提供协同程序和其他现代在时间和预算内编写高性能应用程序的方法。再一次,go 在 linux 下超级快,这正是它的设计目的(非常高兴)

        【讨论】:

          【解决方案10】:

          Java 和 C 的数据和方法(函数)定义都更加明确。 C 是静态类型的,而 Java 的继承模型则更少。这意味着处理数据的方式在编译期间几乎已经定义。

          Go 的数据和函数定义更加隐含。内置函数本质上更通用,并且缺少类型层次结构(如 Java 或 C++)给 Go 带来了速度劣势。

          请记住,Google 对 Go 语言的目标是在执行速度和编码速度之间取得可接受的折衷。我认为他们在早期的尝试中达到了一个很好的最佳位置,而且随着更多的工作完成,情况只会有所改善。

          如果您将 Go 与主要优势是编码速度的动态类型语言进行比较,您会看到 Go 的执行速度优势。在您使用的基准测试中,Go 比 perl 快 8 倍,比 Ruby 1.9 和 Python 3 快 6 倍。

          无论如何,要问的更好的问题是 Go 在易于编程与执行速度之间取得了很好的折衷吗?我的回答是肯定的,它应该会变得更好。

          【讨论】:

          • “缺乏类型层次结构(如 Java 或 C++)给 Go 带来了速度劣势”—wut?
          • “Go 的数据和函数定义更加隐含。”不正确。你的意思是类型如何在不明确的情况下实现方法?编译器检测类型 - 接口成员资格。这很快。 “内置函数本质上更通用”不,内置函数像其他所有东西一样被编译。 C++ 模板也会发生同样的事情。 “缺少类型层次结构(如 Java 或 C++)给 Go 带来了速度劣势”——不正确,类型层次结构与运行时执行无关。
          猜你喜欢
          • 2012-05-05
          • 1970-01-01
          • 2021-09-04
          • 2012-05-25
          • 1970-01-01
          • 2020-11-25
          • 1970-01-01
          • 2013-02-22
          • 1970-01-01
          相关资源
          最近更新 更多