代码之家  ›  专栏  ›  技术社区  ›  Ilian Iliev

为什么<比>=

  •  18
  • Ilian Iliev  · 技术社区  · 16 年前

    我正在使用以下代码进行测试,看起来像<慢于>=。,有人知道为什么吗?

    import timeit
    s = """
      x=5
      if x<0: pass
    """
      t = timeit.Timer(stmt=s)
      print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
    #0.21 usec/pass
    z = """
      x=5
      if x>=0: pass
    """
    t2 = timeit.Timer(stmt=z)
    print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000)
    #0.18 usec/pass
    
    7 回复  |  直到 10 年前
        1
  •  32
  •   user326503 user326503    16 年前

    import dis
    def f1():
        x=5
        if x < 0: pass
    
    def f2():
        x = 5
        if x >=0: pass
    
    >>> dis.dis(f1)
      2           0 LOAD_CONST               1 (5) 
                  3 STORE_FAST               0 (x) 
    
      3           6 LOAD_FAST                0 (x) 
                  9 LOAD_CONST               2 (0) 
                 12 COMPARE_OP               0 (<) 
                 15 POP_JUMP_IF_FALSE       21 
                 18 JUMP_FORWARD             0 (to 21) 
            >>   21 LOAD_CONST               0 (None) 
                 24 RETURN_VALUE         
    >>> dis.dis(f2)
      2           0 LOAD_CONST               1 (5) 
                  3 STORE_FAST               0 (x) 
    
      3           6 LOAD_FAST                0 (x) 
                  9 LOAD_CONST               2 (0) 
                 12 COMPARE_OP               5 (>=) 
                 15 POP_JUMP_IF_FALSE       21 
                 18 JUMP_FORWARD             0 (to 21) 
            >>   21 LOAD_CONST               0 (None) 
                 24 RETURN_VALUE         
    

    代码几乎相同,但f1总是运行第15行并跳到21,f2总是运行15->18->21,因此性能应该受到if语句中的true/false的影响,而不是<或>=问题。

        2
  •  5
  •   djna    16 年前

    第一个测试的结果为true,第二个测试的结果为false。结果可能是处理方式略有不同。

        3
  •  5
  •   Duncan    16 年前

    if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
            /* INLINE: cmp(int, int) */
            register long a, b;
            register int res;
            a = PyInt_AS_LONG(v);
            b = PyInt_AS_LONG(w);
            switch (oparg) {
            case PyCmp_LT: res = a <  b; break;
            case PyCmp_LE: res = a <= b; break;
            case PyCmp_EQ: res = a == b; break;
            case PyCmp_NE: res = a != b; break;
            case PyCmp_GT: res = a >  b; break;
            case PyCmp_GE: res = a >= b; break;
            case PyCmp_IS: res = v == w; break;
            case PyCmp_IS_NOT: res = v != w; break;
            default: goto slow_compare;
            }
            x = res ? Py_True : Py_False;
            Py_INCREF(x);
    }
    

    因此,在比较过程中,惟一的变化是通过switch语句的路由,以及结果是真是假。我的猜测是,您只是看到了由于CPU的执行路径(可能还有分支预测)而产生的变化,因此在其他版本的Python中,您看到的效果也可能很容易消失,或者相反。

        4
  •  2
  •   Tim Pietzcker    16 年前

    我刚刚在python3.1.2中尝试过它-没有区别。

    >>> import timeit
    >>> s = """x=5
    ... if x<0: pass"""
    >>> t = timeit.Timer(stmt=s)
    >>> print ("%.2f usec/pass" % (1000000 * t.timeit(number=1000000)/100000))
    1.48 usec/pass
    >>>
    >>> z = """x=5
    ... if x>=0: pass"""
    >>> t2 = timeit.Timer(stmt=z)
    >>> print ("%.2f usec/pass" % (1000000 * t.timeit(number=1000000)/100000))
    0.59 usec/pass
    >>>
    >>> import timeit
    >>> s = """x=5
    ... if x<0: pass"""
    >>> t = timeit.Timer(stmt=s)
    >>> print ("%.2f usec/pass" % (1000000 * t.timeit(number=1000000)/100000))
    0.57 usec/pass
    >>>
    >>> z = """x=5
    ... if x>=0: pass"""
    >>> t2 = timeit.Timer(stmt=z)
    >>> print ("%.2f usec/pass" % (1000000 * t.timeit(number=1000000)/100000))
    1.47 usec/pass
    

    因此,我猜与其他进程的调度冲突是这里的主要变量。

        5
  •  2
  •   Hexagon    16 年前

    试试看-

    import timeit
    
    Times = 30000000
    
    s = """
      x=5
      if x>=0: pass
    """
    
    t1 = timeit.Timer( stmt=s )
    t2 = timeit.Timer( stmt=s )
    t3 = timeit.Timer( stmt=s )
    
    print t1.timeit( number=Times )
    print t2.timeit( number=Times )
    print t3.timeit( number=Times )
    print t1.timeit( number=Times )
    print t2.timeit( number=Times )
    print t3.timeit( number=Times )
    print t1.timeit( number=Times )
    print t2.timeit( number=Times )
    print t3.timeit( number=Times )
    print t1.timeit( number=Times )
    print t2.timeit( number=Times )
    print t3.timeit( number=Times )
    

    在我的机器上,输出是(一致的,并且不管我尝试了多少个循环-所以它可能不会恰好与机器上发生的其他事情一致)-

    1.96510925271
    1.84014169399
    1.84004224001
    1.97851123537
    1.86845451028
    1.83624929984
    1.94599509155
    1.85690220405
    1.8338135154
    1.98382475985
    1.86861430713
    1.86006657271
    

    “t1”总是需要更长的时间。 但是,如果您尝试对调用或对象创建进行重新排序,则情况会有所不同(而且不是我可以轻松解释的模式)。

        6
  •  1
  •   John La Rooy    16 年前

    用IPython我明白了 x<=0 x<0 需要320ns-超过两倍的时间

    其他比较 x>0 x>=0 好像也要300纳秒

    即使超过1000000个循环,结果也会有很大的波动

        7
  •  1
  •   Yann Vernier    16 年前

    这是一个相当有趣的问题。我移除了 if cond: pass 通过使用 v=cond 相反,它并没有完全消除这种差异。我仍然不确定答案,但我找到了一个合理的理由:

    switch (op) {
        case Py_LT: c = c <  0; break;
        case Py_LE: c = c <= 0; break;
        case Py_EQ: c = c == 0; break;
        case Py_NE: c = c != 0; break;
        case Py_GT: c = c >  0; break;
        case Py_GE: c = c >= 0; break;
    }
    

    这是从Objects/object.c函数将\u 3way\u转换为\u object。请注意,>=是最后一个分支;这意味着,单凭它,不需要跳出。中断语句被删除。它和志贵拆卸中的0和5匹配。作为一个无条件中断,它可以由分支预测来处理,但也可能导致要加载的代码更少。

    在这个层次上,差异自然是高度特定于机器的。我的测量不是很彻底,但这是一个点,在C级我看到一个偏差之间的运营商。我可能有一个更大的偏见,从CPU速度缩放。