【发布时间】:2012-10-14 09:57:52
【问题描述】:
注意:我是一名 Ruby 开发人员,试图在 Python 中找到自己的方式。
当我想弄清楚为什么某些脚本使用mylist[:] 而不是list(mylist) 来复制列表时,我对复制range(10) 的各种方法进行了快速基准测试(见下面的代码)。
编辑:我更新了测试以使用 Python 的 timeit,如下所示。这使得无法直接将其与 Ruby 进行比较,因为 timeit 不考虑循环,而 Ruby 的 Benchmark 则考虑了循环,因此 Ruby 代码仅供参考。
Python 2.7.2
Array duplicating. Tests run 50000000 times
list(a) 18.7599430084
copy(a) 59.1787488461
a[:] 9.58828091621
a[0:len(a)] 14.9832749367
作为参考,我也用 Ruby 编写了相同的脚本:
Ruby 1.9.2p0
Array duplicating. Tests 50000000 times
user system total real
Array.new(a) 14.590000 0.030000 14.620000 ( 14.693033)
Array[*a] 18.840000 0.060000 18.900000 ( 19.156352)
a.take(a.size) 8.780000 0.020000 8.800000 ( 8.805700)
a.clone 16.310000 0.040000 16.350000 ( 16.384711)
a[0,a.size] 8.950000 0.020000 8.970000 ( 8.990514)
问题 1:mylist[:] 的不同之处在于它比 mylist[0:len(mylist)] 快 25 %。它是直接复制到内存中还是什么?
问题 2: 编辑: 更新后的基准测试不再显示 Python 和 Ruby 的巨大差异。 是:我是否以某种明显低效的方式实现测试,以至于 Ruby 代码比 Python 快得多?
现在是代码清单:
Python:
import timeit
COUNT = 50000000
print "Array duplicating. Tests run", COUNT, "times"
setup = 'a = range(10); import copy'
print "list(a)\t\t", timeit.timeit(stmt='list(a)', setup=setup, number=COUNT)
print "copy(a)\t\t", timeit.timeit(stmt='copy.copy(a)', setup=setup, number=COUNT)
print "a[:]\t\t", timeit.timeit(stmt='a[:]', setup=setup, number=COUNT)
print "a[0:len(a)]\t", timeit.timeit(stmt='a[0:len(a)]', setup=setup, number=COUNT)
鲁比:
require 'benchmark'
a = (0...10).to_a
COUNT = 50_000_000
puts "Array duplicating. Tests #{COUNT} times"
Benchmark.bm(16) do |x|
x.report("Array.new(a)") {COUNT.times{ Array.new(a) }}
x.report("Array[*a]") {COUNT.times{ Array[*a] }}
x.report("a.take(a.size)") {COUNT.times{ a.take(a.size) }}
x.report("a.clone") {COUNT.times{ a.clone }}
x.report("a[0,a.size]"){COUNT.times{ a[0,a.size] }}
end
【问题讨论】:
-
使用 python
timeitmodule 来测量 python 执行时间。我怀疑它会让事情(很多)更快,但它会避免所有常见的时间陷阱。 -
alist[:]与alist[0:len(alist)]的时差;后者创建 pythonint对象,前一种方法不需要处理。 -
@MartijnPieters -- 后者每次还需要查找全局
len(并调用) -
Array(a)不复制数组。当给定一个数组时,它只调用to_ary,它返回self。您还应该使用Ruby's Benchmark library 而不是手动计时。 -
在 Ruby 中尝试
obj.dup并进行基准测试。