赋值和比较哪个更快? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
atwoodSoInterest
V2EX    编程

赋值和比较哪个更快?

  •  1
     
  •   atwoodSoInterest 2019 年 5 月 23 日 6869 次点击
    这是一个创建于 2516 天前的主题,其中的信息可能已经有所发展或是发生改变。

    coding 中经常遇到一种情况。对一个变量赋值,是直接赋值,还是判断之后再赋值。 体现在代码上,大概是下面这种情况( i 和 num 都是 int ): if (i > 0) num = i; 或者 num = i; 我的疑问是到底哪个更快,自己用 C#做了测试:在循环一亿次的情况下,直接赋值速度更快。但是判断赋值会有部分是执行了 if 中的代码的,所以会导致了实验不纯粹。

    然后我又用下面的代码测试了下,单纯的对比赋值和比较的效率

     static void Main(string[] args) { int num; Console.WriteLine(DateTime.Now.ToString("mm:ss.fff")); for (int i = 0; i < 100000000; i++) { if (i > 1000) { //num = int.MaxValue; } } Console.WriteLine(DateTime.Now.ToString("mm:ss.fff")); Console.WriteLine("---"); Console.WriteLine(DateTime.Now.ToString("mm:ss.fff")); for (int i = 0; i < 100000000; i++) { num = int.MaxValue; } Console.WriteLine(DateTime.Now.ToString("mm:ss.fff")); Console.ReadLine(); } 

    结果发现还是直接赋值更快,在我本机上,判断执行一亿次速度是 226ms,赋值执行一亿次速度是 168ms。(大家也可以自己去 https://try.dot.net/试试)

    最后从结果上来看,在整型的情况下,赋值是会比判断快的。

    但是问题就来了,为什么呢? 我自己脑洞了一个答案,赋值到中间语言的时候就是 mov,比较到中间语言的时候是 cmp,mov 就直接把 01 丢到变量里去就可以了;但是 cmp 的话就要做减法,要做借位啊这那的操作,所以是赋值会更快。

    强行解释了一波,感觉不是很信服。所以还请大家集思广益,破除疑惑~

    23 条回复    2019-05-28 17:56:08 +08:00
    whitev2
        1
    whitev2  
       2019 年 5 月 23 日
    只做判断,分支中没有任何操作,会不会直接把分支优化掉了?
    atwoodSoInterest
        2
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @whitev2 如果是被优化了的话,应该是只做判断的更快才对。现在的现象是,直接赋值更快。
    autoxbc
        3
    autoxbc  
       2019 年 5 月 23 日
    赋值有副作用,就这一条就够了
    marcong95
        4
    marcong95  
       2019 年 5 月 23 日
    因为你有个分支,那就自然多了一个跳转指令了?
    Counter
        5
    Counter  
       2019 年 5 月 23 日
    底层的知识比较薄弱,抱歉不了解。。。
    另外,mvvm 场景如果直接赋值的话,是不是就会有一些后续操作会被触发(比如重新渲染控件)?
    atwoodSoInterest
        6
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @autoxbc 什么副作用呢?不是太明白哎。
    @marcong95 if 分支就是用来测试“比较”操作耗时的,多了一个跳转指令是什么意思啊?
    @Counter mvvm 还是要看具体框架的实现机制了吧
    jmc891205
        7
    jmc891205  
       2019 年 5 月 23 日
    用 c 试了一遍 比较后赋值比赋值快一点
    看 gcc 生成的汇编 前者比后者多一条条件转移指令
    xenme
        8
    xenme  
       2019 年 5 月 23 日
    这很好理解,比较多一个操作,肯定慢

    发现异常的话,一定是有优化了,底层代码的实际逻辑并不是比较后再赋值
    huluhulu
        9
    huluhulu  
       2019 年 5 月 23 日
    多一次比较, 当然比较慢啊. 代码更多, 汇编指令也更多.
    不明白楼主的疑惑在哪里...
    atwoodSoInterest
        10
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @jmc891205 哦~没想到换了语言,结果就不一样了,这真是出乎意料啊。我等下换其他语言试试。我后来的例子里把 “比较后赋值” 换成了 “只比较” ,因为比较后赋值不好比较两个操作的效率。话说,老哥你知道在汇编里,cmp 指令和 mov 指令哪个更快吗?我找了下没找到有相关资料的。
    @xenme 开始的那个例子不太好,就是会有这种迷惑的信息。后来的例子熟练使用了高中学的控制变量法,去掉了赋值这个干扰信息,所以就只是 “比较” 和 “赋值” 这两个操作的速度比较。
    atwoodSoInterest
        11
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @huluhulu 后面的例子里,去掉了赋值,所以就没有“多一次”的操作了。就只是纯粹的“赋值”和“比较”的效率对比。示例代码里已经把判断分支里的赋值操作注释掉啦
    momocraft
        12
    momocraft  
       2019 年 5 月 23 日
    每种 CPU 的各指令所需周期是有资料的

    高级语言+多进程时因素就太多了,我们其实也不知道 CPU 上跑的是什么
    jmc891205
        13
    jmc891205  
       2019 年 5 月 23 日
    atwoodSoInterest
        14
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @jmc891205 就近把上面示例代码翻译成了 js,发现还是赋值快。

    var num = 0;
    console.time('判断操作耗时');
    for (var i = 0; i < 100000000; i++)
    {
    if (i > 1000)
    {
    //没有赋值
    }
    }
    console.timeEnd('判断操作耗时');
    console.log('---');
    console.time('赋值操作耗时');
    for (var i = 0; i < 100000000; i++)
    {
    num = i;
    }
    console.timeEnd('赋值操作耗时');
    VM1182:10 判断操作耗时: 208.4228515625ms
    VM1182:11 ---
    VM1182:17 赋值操作耗时: 168.830078125ms
    undefined
    jmc891205
        15
    jmc891205  
       2019 年 5 月 23 日
    @atwoodSoInterest
    我也不知道诶 可能有两个原因
    一是我把两段写在两个文件里 分别编译后在命令行里用 time 统计的时间
    二是我是在一台 CPU 是 Intel Xeon 系列的服务器上测试的
    jmc891205
        16
    jmc891205  
       2019 年 5 月 23 日
    @atwoodSoInterest

    糟糕 是我看错结果了。。。
    我也是赋值比较快
    sorry
    hmzt
        17
    hmzt  
       2019 年 5 月 23 日
    @momocraft 是可以查到,不过依然不能解除疑惑,80386 的 mov 指令,从内存 mov 到寄存器要 4clock,反过来就只要 2 个 clock,为什么读取内存的用时是写入的两倍( https://pdos.csail.mit.edu/6.828/2007/readings/i386/MOV.htm)

    不过就楼主的问题,理论上赋值更快
    赋值
    mov eax, a
    mov b, eax
    比较
    mov eax, a
    cmp b, eax
    yejinmo
        18
    yejinmo  
       2019 年 5 月 23 日
    抛去哪个快的疑问,比较后再赋值应该更符合逻辑吧,比如存在 setter 的这种情况
    atwoodSoInterest
        19
    atwoodSoInterest  
    OP
       2019 年 5 月 23 日
    @jmc891205 哈哈,没关系,难免失手啊。给的资料很棒啊,不过还是没有找到 mov 比 cmp 快的依据。
    @hmzt 看了给的资料,发现资料里写的 cmp 和 mov 都是只用 2clock 啊,为什么一个会更快啊,是我漏了什么细节吗?
    @yejinmo 这只是个比较 geek 的想法,忽然想求索一下。真正 coding 的时候,可读性的优先级是远高于性能的。
    hmzt
        20
    hmzt  
       2019 年 5 月 24 日
    @atwoodSoInterest 因为 cmp 的两个操作数有一个来自内存,所以要 5clock,如果都在寄存器里,确实一样快
    atwoodSoInterest
        21
    atwoodSoInterest  
    OP
       2019 年 5 月 24 日
    @hmzt 这个超出我知识范畴了,是怎么分辨来自内存还是来自寄存器的啊?还请赐教~
    c4f36e5766583218
        22
    c4f36e5766583218  
       2019 年 5 月 28 日
    年轻的时候我也纠结过这个问题。
    atwoodSoInterest
        23
    atwoodSoInterest  
    OP
       2019 年 5 月 28 日
    @c4f36e5766583218 哈哈,所以纠结的结果呢
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2937 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 09:43 PVG 17:43 LAX 02:43 JFK 05:43
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86