这个问题之后的讨论让我感到疑惑,所以我决定运行一些测试,比较set((x,y,z))
和{x,y,z}
在Python中创建集合的创建时间(我使用的是Python3.7)。
我比较了使用time
和timeit
的两种方法。这两项结果均与以下结果一致*:
test1 = """
my_set1 = set((1, 2, 3))
"""
print(timeit(test1))
结果:0.30240735499999993
test2 = """
my_set2 = {1,2,3}
"""
print(timeit(test2))
所以第二种方法几乎比第一种方法快3倍。这对我来说是一个很大的差别。通过这种方式优化set文字相对于set()
方法的性能,究竟是怎么回事?在哪些情况下,哪一个是可取的?
*注意:我只显示timeit
测试的结果,因为它们是对许多样本进行平均的,因此可能更可靠,但使用time
进行测试时的结果在这两种情况下显示出类似的差异。
编辑:我知道这个类似的问题,虽然它回答了我最初问题的某些方面,但它没有涵盖所有问题。问题中没有处理集合,由于空集合在python中没有literal语法,所以我很好奇使用literal创建集合与使用set()
方法有何区别(如果有的话)。此外,我还想知道set((x,y,z)
中元组参数的处理在幕后是如何发生的,以及它对运行时的可能影响是什么。
(这是对已经从初始问题中编辑出来的代码的响应)在第二种情况下,您忘记调用函数了。进行适当的修改,结果如预期的那样:
test1 = """
def foo1():
my_set1 = set((1, 2, 3))
foo1()
"""
timeit(test1)
# 0.48808742000255734
test2 = """
def foo2():
my_set2 = {1,2,3}
foo2()
"""
timeit(test2)
# 0.3064506609807722
现在,时间差异的原因是因为set()
是一个需要查找符号表的函数调用,而{...}
set构造是语法的一个人工产物,速度要快得多。
观察拆解后的字节码,差别就很明显了。
import dis
dis.dis("set((1, 2, 3))")
1 0 LOAD_NAME 0 (set)
2 LOAD_CONST 3 ((1, 2, 3))
4 CALL_FUNCTION 1
6 RETURN_VALUE
dis.dis("{1, 2, 3}")
1 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (2)
4 LOAD_CONST 2 (3)
6 BUILD_SET 3
8 RETURN_VALUE
在第一种情况下,函数调用是由元组(1,2,3)
上的指令call_function
进行的(它也有自己的开销,尽管开销很小--它是通过load_const
作为常量加载的),而在第二种情况下,它只是一个build_set
调用,这样效率更高。
Re:您关于构造元组所花费的时间的问题,我们看到这实际上是可以忽略不计的:
timeit("""(1, 2, 3)""")
# 0.01858693000394851
timeit("""{1, 2, 3}""")
# 0.11971827200613916
元组是不可变的,所以编译器通过将其加载为常量来优化这个操作--这叫做常量折叠(您可以从上面的load_const
指令中清楚地看到这一点),所以所花费的时间可以忽略不计。这一点在集合中看不到,因为它们是可变的(感谢@user2357112指出了这一点)。
对于较大的序列,我们看到类似的行为。{..}
语法使用集合理解构造集合的速度更快,而set()
语法则必须从生成器生成集合。
timeit("""set(i for i in range(10000))""", number=1000)
# 0.9775058150407858
timeit("""{i for i in range(10000)}""", number=1000)
# 0.5508635920123197
作为参考,您还可以在更近期的版本上使用可迭代解包:
timeit("""{*range(10000)}""", number=1000)
# 0.7462548640323803
然而,有趣的是,set()
在range
上直接调用时速度更快:
timeit("""set(range(10000))""", number=1000)
# 0.3746800610097125
这恰好比设定的构建更快。您将看到其他序列(如list
s)的类似行为。
这个问题在StackOverflow上被问过很多次,但没有一次是基于性能的。 在《Effective Java书籍》中给出了 改进的版本简单如下:此版本使用单个String实例,而不是每次执行时都创建一个新的String实例。 因此,我尝试了这两种方法,发现性能有了显著改善: 大约需要399 372纳秒。 为什么会有这么多的性能提升?内部是否发生了编译器优化?
本文向大家介绍set rs=conn.execute,set rs=server.createobject(“ADODB.recordset”)的性能对比,包括了set rs=conn.execute,set rs=server.createobject(“ADODB.recordset”)的性能对比的使用技巧和注意事项,需要的朋友参考一下 经常用asp的同行,可能会建议用set rs=conn.
更新:为了更明显地说明我正在努力做的事情:我将拥有5000万以上的设备流媒体音频。流平均为100KB,峰值流量时为200K流/分钟。我正在寻找一种存储解决方案来满足这种需求。我一直在研究Bookkeeper、Kafka、Ignite、Cassandra和Redis。到目前为止,我只对redis和ignite进行了基准测试,但我很惊讶ignite这么慢。
问题内容: 几天前,我开始使用新的OpenCV-Python界面。 我的问题是关于和接口的比较。 关于易用性,新界面得到了更大的改进,并且使用起来确实非常容易和有趣。 但是速度呢? 我制作了两个小代码段,一个在另一个中,以检查性能。两者具有相同的功能,访问图像的像素,对其进行测试,进行一些修改等。 下面是代码: : =========================================
对于一个对象,有多个字段,其中有一些字段使用的频率比较高,而一些字段使用的频率很低。现在是都建在一个集合内,并使用 filter 获取到要使用的字段。还是把使用频率低的字段提取出来,生成一个新的集合,然后使用外键的方法进行引用。请问哪一种方法性能比较好
问题内容: 我建立了一个分析引擎,可以从数据库中提取50-100行原始数据(称为),在PHP上对其进行一堆统计测量,然后精确给出140个数据点,然后将它们存储在另一个表中(让我们称之为)。所有这些数据点都是非常小的整数(“ 40”,“ 2.23”,“-1024”是数据类型的很好的示例)。 我知道mysql的最大列数非常高(4000+),但是当性能真正开始下降时,似乎有很多灰色区域。 这里有一些关于