V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
chaoschick
V2EX  ›  程序员

相同的 for 循环 为什么 Java 比 c 的速度快?

  •  
  •   chaoschick · 2023-12-26 16:29:53 +08:00 · 3896 次点击
    这是一个创建于 368 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Java

    public class DuffDevice {

    private static int duff2(int count) {
    int i = 0;
    do {
    ++i;
    } while (--count >0);
    return i;
    }

    public static void main(String[] args) {
    int duff;
    long start, end;
    DuffDevice duffDevice = new DuffDevice();

    start = System.currentTimeMillis();
    duff = duff2(Integer.MAX_VALUE - 7);
    end = System.currentTimeMillis();
    System.out.println(duff + " " + (end - start) + " ms");
    }
    }

    C
    #include <sys/time.h>
    #include <stdio.h>

    int duff(int count) {
    }

    int main(int argc, char* argv[]) {
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    long count = 2147483640;
    long i = 0;

    do {
    ++i;
    } while (--count);

    gettimeofday(&end_time, NULL);

    int total_time = 1000000 * (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec);
    printf("%d us", total_time);
    printf("\n");
    printf("%.3f ms", (double) total_time / 1000);
    printf("\n");

    printf("%l", i);
    return 0;
    }

    Java 耗时情况
    2 ms

    C 耗时情况
    4638.628 ms

    性能怎么会相差这么大?
    23 条回复    2023-12-27 14:32:47 +08:00
    xtreme1
        1
    xtreme1  
       2023-12-26 16:37:10 +08:00   ❤️ 3
    tool2d
        2
    tool2d  
       2023-12-26 16:42:33 +08:00   ❤️ 1
    @xtreme1 被完全优化掉的不算。


    long i = 0;
    改成
    volatile long i = 0;

    时间就正常了。
    chaoschick
        3
    chaoschick  
    OP
       2023-12-26 16:42:45 +08:00
    @xtreme1 能解释一下为什么两者性能如此悬殊的原因吗
    chaoschick
        4
    chaoschick  
    OP
       2023-12-26 16:43:15 +08:00
    @tool2d 我试试
    hefish
        5
    hefish  
       2023-12-26 16:43:16 +08:00
    java 的编译器高级。全优化掉了。
    chaoschick
        6
    chaoschick  
    OP
       2023-12-26 16:45:21 +08:00
    @tool2d [admin@iZt4ngr7j75qbzgg9ilsifZ c]$ cat duff2.c
    #include <sys/time.h>
    #include <stdio.h>

    int main(int argc, char* argv[]) {
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    long count = 2147483640;
    volatile long i = 0;

    do {
    ++i;
    } while (--count);

    gettimeofday(&end_time, NULL);

    int total_time = 1000000 * (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec);
    printf("%d us", total_time);
    printf("\n");
    printf("%.3f ms", (double) total_time / 1000);
    printf("\n");

    printf("%l", i);
    return 0;
    }
    [admin@iZt4ngr7j75qbzgg9ilsifZ c]$ gcc duff2.c && ./a.out
    4621705 us
    4621.705 ms
    wdlth
        7
    wdlth  
       2023-12-26 16:47:26 +08:00
    我在我的电脑测试结果是:
    0 us
    0.000 ms
    tool2d
        8
    tool2d  
       2023-12-26 16:48:17 +08:00
    @chaoschick 4 秒正常的啊,我这里也是 4 秒。

    0 秒那种都是编译器把循环优化掉了。
    diivL
        9
    diivL  
       2023-12-26 16:51:33 +08:00
    gcc duff2.c -O3 && ./a.out
    chaoschick
        10
    chaoschick  
    OP
       2023-12-26 16:53:53 +08:00
    public class DuffDevice {

    private static long duff2(long count) {
    long i = 0;
    do {
    ++i;
    } while (--count >0);
    return i;
    }

    public static void main(String[] args) {
    long duff;
    long start, end;
    DuffDevice duffDevice = new DuffDevice();

    start = System.currentTimeMillis();
    duff = duff2((long) Integer.MAX_VALUE - 7);
    end = System.currentTimeMillis();
    System.out.println(duff + " " + (end - start) + " ms");
    }
    }

    输出
    2147483640 639 ms

    我改了一下 i 值的类型 耗时 变长了
    所以 应该没把循环优化掉吧
    chaoschick
        11
    chaoschick  
    OP
       2023-12-26 16:54:44 +08:00
    @diivL [admin@iZt4ngr7j75qbzgg9ilsifZ c]$ gcc duff2.c -O3 && ./a.out
    3688484 us
    3688.484 ms
    diivL
        12
    diivL  
       2023-12-26 16:58:26 +08:00   ❤️ 1
    @chaoschick 你用的是 #6 的代码吗? 用你主贴的代码,然后用 gcc duff2.c -O3 && ./a.out
    chaoschick
        13
    chaoschick  
    OP
       2023-12-26 17:12:04 +08:00
    @diivL #include <sys/time.h>
    #include <stdio.h>

    int main(int argc, char* argv[]) {
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    long count = 2147483640;
    long i = 0;

    do {
    ++i;
    } while (--count);

    gettimeofday(&end_time, NULL);

    int total_time = 1000000 * (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec);
    printf("%d us", total_time);
    printf("\n");
    printf("%.3f ms", (double) total_time / 1000);
    printf("\n");

    printf("%l", i);
    return 0;
    }
    [admin@iZt4ngr7j75qbzgg9ilsifZ c]$ gcc duff2.c -O3 && ./a.out
    1 us
    0.001 ms

    这是优化掉 for 循环了吗?
    Ericcccccccc
        14
    Ericcccccccc  
       2023-12-26 20:22:00 +08:00
    在 main 里做性能测试是无效行为.

    而且 java 里有各种 jit, osr 之类的高级优化手段
    iseki
        15
    iseki  
       2023-12-26 21:23:09 +08:00 via Android
    此外 Java 的 volatile 有额外的语义,所以也没法和 C 对应,这样做 microbench 可能你们很难说明什么问题
    msg7086
        16
    msg7086  
       2023-12-26 21:51:20 +08:00
    > 为什么
    因为优化不一样。如果 Java 比 C 快很多,那说明 Java 上优化得比 C 狠,反之亦然。
    Inn0Vat10n
        17
    Inn0Vat10n  
       2023-12-26 22:22:54 +08:00
    你这里出现这么离谱的结果, 首要原因是编译 C 代码时没开优化
    Cookmilk
        18
    Cookmilk  
       2023-12-27 02:09:46 +08:00 via iPhone
    C 是直接跑在电脑的 CPU 里,java 跑在虚拟机 CPU 里。测试 for 循环毫无意义。应该测试某一个算法。比如加密算法或者 md5 等等
    mangojiji
        19
    mangojiji  
       2023-12-27 05:41:29 +08:00
    又见达夫设备。 ...
    chaoschick
        20
    chaoschick  
    OP
       2023-12-27 07:45:36 +08:00 via Android
    以前我一直以为编译器优化能提升的性能很小,这次真是长见识了
    PTLin
        21
    PTLin  
       2023-12-27 09:16:27 +08:00
    这种代码不长的,而且是循环引起的性能问题,建议直接看汇编/字节码,来确定问题以及验证猜想。
    或者用完整的性能测试框架测试,避免出现一个优化后测试的,一个还是调试模式测试的的这种低级问题。
    debuggerx
        22
    debuggerx  
       2023-12-27 10:04:17 +08:00
    [为什么下面程序递归计算斐波那契数列 java 比 c++要快 - RednaxelaFX 的回答]( https://www.zhihu.com/question/56683164/answer/150190561)
    LiaoMatt
        23
    LiaoMatt  
       2023-12-27 14:32:47 +08:00
    C 代码的变量用 register 修饰会不会更快
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   930 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 20:40 · PVG 04:40 · LAX 12:40 · JFK 15:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.