【问题标题】:Loop control, what is more efficient循环控制,什么更高效
【发布时间】:2010-11-04 21:30:01
【问题描述】:

以下两种选择中哪一种更有效?有什么进一步改进的建议吗?

备选方案 A:

for i in BAR_Items:
    if BAR_Items[i] != A and SHAPE[i+"_SHP"] != A: continue
    if i in Selection:
        Selection.remove(i)
        BAR_Items[i].clearActions()
        BAR_Items[i].add(vizact.spinTo(axisAngle=[0,1,0,90],speed=300))
        VFrame.SetStatusText(frame, i + " has been deselected. "+ str(Selection))
    else:
        Selection.append(i)
        BAR_Items[i].add(vizact.spin(0,1,0,90,viz.FOREVER))
        VFrame.SetStatusText(frame, i + " selected. " + str(Selection))
    break

备选方案 B:

for i in BAR_Items:
    if BAR_Items[i] == A or SHAPE[i+"_SHP"] == A:
        if i in Selection:
            Selection.remove(i)
            BAR_Items[i].clearActions()
            BAR_Items[i].add(vizact.spinTo(axisAngle=[0,1,0,90],speed=300))
            VFrame.SetStatusText(frame, i + " has been deselected. "+ str(Selection))
        else:
            Selection.append(i)
            BAR_Items[i].add(vizact.spin(0,1,0,90,viz.FOREVER))
            VFrame.SetStatusText(frame, i + " selected. " + str(Selection))
        break

好的,我按照建议找到了计时方法。测量 500 次后,B(0.001279264 秒)平均比 A(0.001966169 秒)快(数字为平均值)。

【问题讨论】:

  • 当你测量它们时,你学到了什么?请包括运行这些的时间信息。
  • @S.Lott:@relima:除了特殊情况,它还会运行吗?使用列表中的索引和项目是错误的。
  • @pyfunc:“它会运行吗”?很重要。所有“什么更有效”的问题都应包含指标,以表明 (a) 它实际运行和 (b) 哪个更有效。
  • @S.Lott,我正在努力争取在这里跑步,但我不确定它会不会。这段代码在实例化的 opengl 引擎中运行,并且 timit 有问题;我将尝试在更大的 opengl 函数之外重写它,但是不会创建对象并且可能会产生不同的结果。但是,代码总是运行,看起来 A 给了我更高的帧速率。
  • @S.Lott,刚刚测量。 B 比 A 快。

标签: python performance loops


【解决方案1】:

测试效率的最佳方法之一是使用timeit 模块。我会将每个备选方案放在一个函数中,在每个函数上运行 timeit,然后进行比较。

【讨论】:

    【解决方案2】:

    好的,这是一种人为的方式来查看性能。由于我们试图查看使用“继续”或将代码拉入“if 块..”之间的区别

    这是一个小实验。

    def f():
        x = {'a':'b', 'c':'d', 'e':'d'}
        for l in x:
            if x[l] != 'd': continue
            print x
    
    def f1():
        x = {'a':'b', 'c':'d', 'e':'d'}
        for l in x:
            if x[l] == 'd':
                print x       
    
    import dis
    print dis.dis(f)   
    print dis.dis(f1)  
    

    大部分操作都是一样的,这里有一个小区别:

    如果是 f:

    56 POP_TOP             
    57 JUMP_ABSOLUTE           34
    60 JUMP_FORWARD             1 (to 64)
    63 POP_TOP             
    
    64 LOAD_FAST                0 (x)
    67 PRINT_ITEM          
    68 PRINT_NEWLINE       
    69 JUMP_ABSOLUTE           34
    72 POP_BLOCK           
    73 LOAD_CONST               0 (None)
    76 RETURN_VALUE  
    

    在 f1 的情况下:

    56 POP_TOP             
    
    57 LOAD_FAST                0 (x)
    60 PRINT_ITEM          
    61 PRINT_NEWLINE       
    62 JUMP_ABSOLUTE           34
    65 POP_TOP             
    66 JUMP_ABSOLUTE           34
    69 POP_BLOCK           
    70 LOAD_CONST               0 (None)
    73 RETURN_VALUE 
    

    判决

    只有一个 OP 差异。真的不太对。有等价的。根据可读性而非性能做出决定。

    【讨论】:

    • My Bar_items 实际上是一个返回对象的字典。 A 是与之比较的对象。
    • @pyfunc,我认为你有一个错误。 f 打印 x >= 1f1 打印 x < 2
    • 而且您的索引变量正在得到优化,因为您从未使用过它。在for l in x: 之后,您引用x 作为索引变量。
    • @aaronasterling:谢谢!我纠正了它。我知道这有点做作。但差别就这么大吗?
    【解决方案3】:

    对于性能不是绝对关键的代码,问问自己“哪个更容易理解”并将其作为您的答案。几微秒的差异根本不值得花时间在脚本代码中烦恼。

    【讨论】:

    • 到目前为止,差异在于我的程序将我的 opengl 刷新率从 90 fps 降至 45 fps,因为差异很小。
    • 现在,在我这个阶段,这不是很麻烦,但是当我尝试渲染更多的动画对象时,它肯定会影响我。
    • @relima:你真的是说只添加 continue 语句就能将刷新率提高 100%?根据 pyfunc 的回答,区别在于单个操作码。即使运行数百万次,我也不知道它是如何产生这种效果的。无论如何,在编写性能关键代码时,“哪个更快”的唯一答案是为您自己的代码计时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    • 2018-05-25
    • 2022-11-10
    相关资源
    最近更新 更多