V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
LeeReamond
V2EX  ›  分享创造

关于哪种语言速度执行速度最快,画了张图表,顺带吐槽

  •  1
     
  •   LeeReamond · 2021-05-16 05:48:27 +08:00 · 6430 次点击
    这是一个创建于 1321 天前的主题,其中的信息可能已经有所发展或是发生改变。

    起因:昨天论坛老哥分享 Python 性能提升计划,其中一些涉及性能的讨论,27 楼老哥自己画了个图表看起来挺不错的。原贴链接

    我个人是因为对 python 性能提升很感兴趣,对其他语言的语言性能比较也很感兴趣,有大版本更新的时候都会搞一些简单算法看看到底快了多少。这回看到这个老哥的图感觉挺不错的,该老哥称自己定期爬取 the benchmarks ganme 画出来的图,我感觉不如直接搞成一个自动维护项目,以后也省得手贱再自己动手跑了。

    鼓捣了一下,大概思路就是基于 github 的分发特性,一个图片链接可以一直保持在最新数据,然后我在原版数据的基础上添加了两个 python 的 jit 解释器( pypy 和 pyston ),最后结果如下:

    数据来源 https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html

    =====================

    几点说明:

    1 、语言性能讨论一直是引战话题,我不是很理解为什么有人会在这个问题上被摸到 G 点,为了避免被喷,我先声明我这个不是严谨性能测试,只是基于开源跑分的爬虫并绘制图表而已。这个项目产生的原因是希望为需要的人提供一些定性结论(或者是定性结论的参考,毕竟它有可能不准),而不是严谨的定量结论。

    2 、以前虽然跟别人讨论经常引用 the benchmarks game 的结论,但从来没仔细研究过这个网站。这次顺带仔细看了一下算法,我觉得它这些设计有几个可能本身也并不严谨。本身对比语言性能就是很难设计的一件事,理解。

    3 、我在做这张图表的时候遇到一个统计学问题,由于一张图里要汇总多项测试的平均水平,一个最简单的想法是求平均耗时。但是需要考虑到一种极端情况就是,假设大部分测试都以非常短的耗时(比如 10 秒以内)完成,而个别测试极端情况的项目的总体时间消耗都很高(比如超过 600 秒),那么如果单纯做加和的话,整体的平均值会很大程度上取决于这个极端情况的结果,而削减了其他项目的影响力,为了避免这种情况发生,需要对数据加权。

    我的方案是采用了如下图所示的运算得到最终结果,其中σ是方差,L 是常数,V 代表输出值。

    大体思路就是,当一个项目整体测试时间较长的时候,我们会略微削弱这个项目的权重,让他不要影响那么大。同时考虑到如果用离散度描述整体测试时间的跨度,方差的比例差可能是一个非常大的数,所以需要进行某种压限,以确保权重最低的项目不会比权重最高的项目低出太多。算法是拍脑袋想的,有兴趣的欢迎看源码,或提意见。

    4 、the benchmarks game 这个网站算是比较熟了,隔一段时间总会看到,但是说实话这次跑出来比例挺多反常识的,大概有以下几点:

    • Java 比 Go 快,而且领先幅度不小。
    • Go 和 javascript 速度居然差不多。
    • Python 比 Ruby 快,而且领先还有一定幅度,我印象中最近一两年听说的都是 ruby 比 python 快一丢丢。
    • Pypy 出乎意料的慢,打破固有印象。我印象中 Pypy 不会比 java 慢出 8 倍。
    • c++和 c 的差距比我想想中大很多,倒是 rust 确实符合印象,也许逐渐蚕食 c++的市场也是必然。

    我后面手动检查了一下数据,应该不是我写错了,确实测试结果加权平均算下来就是这样的,可能是由于这个跑分本身也没那么严谨,或者是特定语言在一些大量使用场景(比如正则)有让效率接近原生级的优化所导致的。

    第 1 条附言  ·  2021-05-16 16:42:45 +08:00
    仓库地址
    https://github.com/GoodManWEN/Programming-Language-Benchmarks-Visualization

    看了一眼好像发帖的时候忘贴了,我说怎么有人问到实现细节。。一共几行代码
    44 条回复    2021-05-18 18:35:12 +08:00
    Leviathann
        1
    Leviathann  
       2021-05-16 06:07:25 +08:00
    ghc 好强啊
    woodfly
        2
    woodfly  
       2021-05-16 06:16:00 +08:00
    我觉得计算时间排名的时候,可以把各个单项测试的时间全部折算成 C++运算时间的倍数,然后求各个测试成绩的平均值作为该语言的成绩。
    pkookp8
        3
    pkookp8  
       2021-05-16 06:39:09 +08:00 via Android
    为什么 c++比 c 快,打破了我的直觉
    hoyixi
        4
    hoyixi  
       2021-05-16 07:26:55 +08:00
    Ruby 慢是早就存在的业界共识
    noe132
        5
    noe132  
       2021-05-16 07:52:46 +08:00
    js 经过 jit 优化后的代码效率非常高,和 native 属于一个梯度的,和编译语言性能不会拉开太大差距。当然要代码质量高,能够被优化才行
    des
        6
    des  
       2021-05-16 08:36:43 +08:00 via iPhone   ❤️ 1
    和我预期不一样
    PHP 这么快,lua 这么慢?
    plko345
        7
    plko345  
       2021-05-16 08:42:21 +08:00 via Android
    py3 比 py2 慢这么多?为什么,原理是啥?不是质疑,就是好奇
    stephenyin
        8
    stephenyin  
       2021-05-16 08:49:16 +08:00
    pyston 是啥?
    voiyy
        9
    voiyy  
       2021-05-16 09:04:13 +08:00
    这个网站的数据并不是很准,rust 好多代码还是调用优化的 c 库,然后跟 c 手写的算法比跑分
    SuperMild
        10
    SuperMild  
       2021-05-16 09:24:15 +08:00
    符合我的印象,Java 比 Go 快一丁点,Go 比 V8 快一丁点,(但如果看内存占用,Go 会比 Java 少很多,也比 Node 少一些),Ruby 垫底,Python 比 Ruby 快一丁点(但也非常慢),但 Python 很多时候会通过调用 C 来提高速度,因此现实中 Python 还是很堪用。
    aristolochic
        11
    aristolochic  
       2021-05-16 09:57:47 +08:00
    @SuperMild 其实 Ruby 也是,而且应用广泛到在 Windows 上都不好装(因为要编译
    毕竟 Ruby 和 Python 都用的是 libffi,而且 libffi 的 gem 封装 ffi 还可以适用于 JRuby 和 Rubinius
    ( libffi 用的实在太广泛了

    除了拉原生扩展这个外援之外,动态语言还是比比什么抽象表达能力、类型标注什么的比较带劲
    046569
        12
    046569  
       2021-05-16 10:12:21 +08:00
    https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/ruby-python3.html

    以 LZ 引用的同一站点页面为例,Ruby 的速度是 Python 的多少倍:

    n-body:2.4
    binary-trees:2.1
    fannkuch-redux:1.9
    fasta:1.4
    spectral-norm:1.0
    reverse-complement: 0.6
    mandelbrot:0.6
    k-nucleotide:0.6
    pidigits:0.6
    regex-redux:0.1

    换句话说,Python 的最大优势项目速度是 Ruby 的十倍,而 Ruby 的最大优势项目速度是 Python 的二十四倍。

    LZ 的加权算法导致结果有失公允。
    hronro
        13
    hronro  
       2021-05-16 10:39:21 +08:00
    @des #6 最近 PHP 性能进步不小,Lua 这里应该用的是原版 Lua 而不是 LuaJIT 。
    hronro
        14
    hronro  
       2021-05-16 10:40:25 +08:00
    确实楼主的加权合不合理还有待商榷,建议楼主可以做加权和不加权的两个版本
    Anybfans
        15
    Anybfans  
       2021-05-16 10:44:05 +08:00
    @plko345 #7 不是 py2 是 pyston 吧
    des
        16
    des  
       2021-05-16 10:52:09 +08:00 via iPhone
    @hronro
    php 是 jit 的原因吗?我怎么记得有人说 php jit 提升不大?
    hronro
        17
    hronro  
       2021-05-16 11:03:46 +08:00
    @des #16
    JIT 对于纯 CPU 的运算提升还是很大的,但对于做 Server 这种大多在做 I/O 的提升就不大,影响 Server 性能的最大因素还是并发模型。而 PHP 的主要用途基本还是在做 Server 吧,所以可以理解成 JIT 对于 PHP 的主要用途提升不大。
    yekern
        18
    yekern  
       2021-05-16 12:12:44 +08:00
    两种权重比法啊
    一种原生语言没有经过任何三方优化的编译器 jit 等等
    一种加持各种优化 例如 PHP 早期的 hhvm 和 现在的 swoole 等等 python 的 pypy 等等
    这就是一种参考,就像有人说过这么一句话 任何一门语言写的项目很少能达到语言本身的瓶颈
    lovestudykid
        19
    lovestudykid  
       2021-05-16 12:14:11 +08:00
    接近底层的编译型语言,应该不会差出好几倍。如果差得多了,多半是程序写得实际不一样。
    Building
        20
    Building  
       2021-05-16 12:28:25 +08:00 via iPhone
    Objective-C 不配拥有名字吗?
    Cbdy
        21
    Cbdy  
       2021-05-16 12:59:50 +08:00
    其实很合理,不是 Go 慢,而是 JavaScrip/V8 快,而做 V8 的人以前是做 JVM 的,就很合理了
    zagfai
        22
    zagfai  
       2021-05-16 13:24:38 +08:00
    有啥意义??
    missdeer
        23
    missdeer  
       2021-05-16 13:36:45 +08:00
    C++比 C 快出乎我的意料
    最近我观察到 C++写的 notepad++在冷加载时往往很慢,但是 C 写的 notepad2 任何时候都很快(它貌似还有汇编级的指令集优化),我就以为随手写的 C 比随手写的 C++要快不少
    xinyana
        24
    xinyana  
       2021-05-16 14:26:26 +08:00 via Android
    不太关心快不快,实现功能就行
    chaowang
        25
    chaowang  
       2021-05-16 14:43:33 +08:00
    我也好奇,为啥 cpp 比 c 还快
    des
        26
    des  
       2021-05-16 15:01:30 +08:00
    toptyloo
        27
    toptyloo  
       2021-05-16 15:02:12 +08:00
    java 不考虑启动 JVM 确实是很快的。
    ipwx
        28
    ipwx  
       2021-05-16 15:09:03 +08:00
    @pkookp8 C++ 追求的 zero-cost abstract,template 大法超级给力。

    举个例子,std::sort(vec.begin(), vec.end(), [&](const auto& lhs, const auto& rhs) { return lhs < rhs; });

    这里的比较器直接被 C++ 编译器内联了(开 -O2 )。如果是 C 语言版本的快排:

    bool fn(const void* a, const void *b)
    qsort(..., &fn);

    函数指针丢进去。除非给每个函数写特殊规则(比如 qsort 是库函数说不定还有机会),一般函数根本没有内联优化的可能性。

    ====

    再比如 C++ 17 的各种骚操作,例如:

    inline constexpr size_t pow2(int n) { return n == 0 ? 1 : 2 * pow2(n-1); }

    ...

    template <int N>
    if constexpr (pow2(N) > 1024) {
    ... branch A
    } else {
    ... branch B
    }

    这段代码,pow2 和 constexpr 都是编译期就确定的行为,不会在运行时计算。
    jhdxr
        29
    jhdxr  
       2021-05-16 15:11:08 +08:00
    @des 我倒不认为是 jit 的原因,php 本身实现的时候就用了不少 trick 去提升性能(举个栗子,在编译期间,部分热点函数的调用,会被替换为一些(专门针对这些函数编写的) opcode ),但这种 trick 是好是坏就见仁见智了。。。


    @SuperMild V8 作为解释型能那么快我还是很震惊的。就算 JIT 也不可能转换所有代码。
    ipwx
        30
    ipwx  
       2021-05-16 15:12:52 +08:00
    @missder @chaowang C++ 的一些评论见我上面的楼。

    另外编辑器的问题,我觉得是作者设计上和实现上偷懒了。C++ 最快的写法写起来还挺累人的,各种奇迹淫巧那不是炫技,而是用了就比 C 快,不用就比 C 慢很多。我写 C++ 经常不开优化比开优化慢 5 ~ 10 倍。

    另外面向优化写代码必须消除 warning,任何 C++ 标准未定义行为都要绕道走。网上不也很多段子,什么什么公司的代码一开优化就崩溃么 2333 。
    3dwelcome
        31
    3dwelcome  
       2021-05-16 15:18:26 +08:00 via Android   ❤️ 2
    楼上打那么多字是认真的吗?
    楼主链接有提供源代码,花十秒点进去看一下,就知道为什么 c++比 c 快了。
    就是一个用了 simd 指令,另一个没用。
    marcushbs
        32
    marcushbs  
       2021-05-16 15:23:04 +08:00
    Ruby 3 jit 出来好久了,就没人想起来更新一下
    matrix67
        33
    matrix67  
       2021-05-16 15:24:47 +08:00
    有没有最赚钱的语言排行,单位行数赚钱比
    Jooooooooo
        34
    Jooooooooo  
       2021-05-16 15:53:47 +08:00
    java 没有 jit 基本没法用
    namelosw
        35
    namelosw  
       2021-05-16 16:26:23 +08:00
    Node.js 是个狠人啊…
    LeeReamond
        36
    LeeReamond  
    OP
       2021-05-16 16:29:59 +08:00 via Android
    @marcushbs 我这个项目可以自己加解释器,新增加语言不太行,因为需要自己实现算法,新加解释器比较简单,有需要欢迎 pr
    LeeReamond
        37
    LeeReamond  
    OP
       2021-05-16 16:32:50 +08:00 via Android
    @des 因为他原版已经画了这种图了,再画一遍意义不大,而且我希望我各个项目能提供直观结论,一眼能看出差多少倍那种的
    LeeReamond
        38
    LeeReamond  
    OP
       2021-05-16 16:35:46 +08:00 via Android
    @hronro 我的想法是如果做图的人自己都没有结论,还需要用户去自行筛选,那失去了简明的初衷,如果算法有问题可以修改算法,不应该做两个版本留给用户
    akira
        39
    akira  
       2021-05-16 17:30:46 +08:00
    原生 快于 解释
    chengxiao
        40
    chengxiao  
       2021-05-17 09:55:00 +08:00
    .net 和 java 先把虚拟机去了再跟人比较快慢吧
    shyrock
        41
    shyrock  
       2021-05-17 18:15:08 +08:00
    @046569 #12 2.4 的意思是 24 倍?我懵了
    monkeyNik
        42
    monkeyNik  
       2021-05-18 18:24:54 +08:00
    @pkookp8 只能说些垃圾代码的太多,拖了后腿
    lesismal
        43
    lesismal  
       2021-05-18 18:28:49 +08:00
    “Java 比 Go 快,而且领先幅度不小。”
    —— 这是错觉。

    全部对比应该是在这里吧:
    https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/go.html

    这是 go 和 java 对比的,大部分测试项 cpu 消耗其实各有千秋,最后两个测试项差距确实很大,但是,稍微修改下再对比:

    以最后一项的 binary-trees 为例( go 耗时 12.80s ,java 耗时 2.48s ):

    go 代码修改:
    func inner(depth, iterations uint32) string {
    chk := uint32(0)
    tree := bottomUpTree(depth) // 这里从循环内移到了循环外
    for i := uint32(0); i < iterations; i++ {
    chk += itemCheck(tree)
    }
    return fmt.Sprintf("%d\t trees of depth %d\t check: %d",
    iterations, depth, chk)
    }

    java 代码修改:
    for (int d = MIN_DEPTH; d <= maxDepth; d += 2) {
    final int depth = d;
    EXECUTOR_SERVICE.execute(() -> {
    int check = 0;

    final int iterations = 1 << (maxDepth - depth + MIN_DEPTH);
    final TreeNode treeNode1 = bottomUpTree(depth); // 这里从循环内移到了循环外
    for (int i = 1; i <= iterations; ++i) {
    check += treeNode1.itemCheck();
    }
    results[(depth - MIN_DEPTH) / 2] =
    iterations + "\t trees of depth " + depth + "\t check: " + check;
    });
    }

    我对 java 不熟,猜测 java 的编译器对 for 循环内局部对象甚至 tree 的构造过程做了复用优化

    因为这种简单逻辑内的遍历,更成熟的老龄编译器可能会做更针对的优化,C++比 C 性能强主要就在于现代 C++编译器的优化,并且实际的业务场景,很少有需要这种频繁创建这样深度和节点数量的临时对象,几乎不会遇到这种小代码段级别的优化在实际业务中发挥太大性能优势,所以把遍历的部分构造放在外层时只对比 check 消耗时,性能差不多、在我机器上 go 略好。

    语言、编译器有一个漫长的成长阶段,go 会越来越强的
    lesismal
        44
    lesismal  
       2021-05-18 18:35:12 +08:00
    “Go 和 javascript 速度居然差不多。”
    —— 这个没关系,毕竟 js 逻辑单线程,对多核心的利用能力肯定是不如 go 的,有人可能说 js 可以开多进程,但是 go 相比多进程还有内存共享、无需通信的优势,在面对更复杂业务功能时还是要强于 js 。所以单就服务端领域,抛开什么社区轮子或者说用 node 弱全栈配合写前端的优势,纯做服务器,go 还是比 js 强大太多,否则 node 爹当年也不会在熟悉了 go 之后感慨 node 不适合做服务器、而是适合辅助前端开发
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5695 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 02:58 · PVG 10:58 · LAX 18:58 · JFK 21:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.