【发布时间】:2017-06-28 19:51:26
【问题描述】:
def sieve(n):
nums = [0] * n
for i in range(2, int(n**0.5)+1):
if nums[i] == 0:
for j in range(i*i, n, i):
nums[j] = 1
return [i for i in range(2, n) if nums[i] == 0]
def sieve_var(n):
nums = [0] * n
for i in range(3, int(n**0.5)+1, 2):
if nums[i] == 0:
for j in range(i*i, n, i):
nums[j] = 1
return [2] + [i for i in range(3, n, 2) if nums[i] == 0]
在我的机器上,sieve(10**8) 需要 2.28 秒,而sieve_var(10**8) 需要 2.67 秒。我不认为 pypy 的预热时间是这里的罪魁祸首,那么为什么不是 sieve_var,它迭代得更少、更快?在标准 python 3.3 中,sieve_var 比预期的更快。在 Windows 8.1 上使用 pypy 4.0.1 32bit。
编辑:作为测试,我在函数的开头添加了count = 0,并在内部循环中添加了count += 1(nums[j] = 1 所在的位置)。 sieve(10**8) 计数为 242570202,而 sieve_var(10**8) 计数为 192570204。因此,尽管 sieve_var 的计数没有减半,但它做的“工作”更少。
为了好玩,这里有一个带有切片索引的版本:
def sieve_slice(n):
sieve = [True] * n
for i in range(3,int(n**0.5)+1,2):
if sieve[i]:
sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
return [2] + [i for i in range(3,n,2) if sieve[i]]
使用 python 3.6,sieve_slice 的运行速度比 sieve 快大约 4 倍,但使用 pypy3 7.3.0,sieve 的运行速度大约是 sieve_slice 的 2 倍。
【问题讨论】:
-
@user2357112 如果错了那为什么
sieve(10**8) == sieve_var(10**8)? -
你是怎么计时的?
-
@user2357112 基本上是
t = time.clock(); print(len(sieve(10**8))); print(time.clock()-t) -
你是否在同一个进程中对这两个调用计时?
-
我可以重现该问题。
len(sieve(2*10**8))大约 6.6 秒,len(sieve_var(2*10**8))大约 7 秒。我在 64 位 Windows 上使用 pypy 5.7.1。
标签: python performance pypy