【问题标题】:Performance of any()any() 的性能
【发布时间】:2014-10-26 22:20:06
【问题描述】:

这主要是一个学习 Python 的练习。我写了这个函数来测试一个数字是否是素数:

def p1(n):
    for d in xrange(2, int(math.sqrt(n)) + 1):
        if n % d == 0:
            return False
    return True

然后我意识到我可以使用 any() 轻松重写它:

def p2(n):
    return not any((n % d == 0) for d in xrange(2, int(math.sqrt(n)) + 1))

在性能方面,我期望 p2 比 p1 更快,或者至少和 p1 一样快,因为 any() 是内置的,但是对于一个大的素数,p2 会慢很多:

$ python -m timeit -n 100000 -s "import test" "test.p1(999983)"
100000 loops, best of 3: 60.2 usec per loop

$ python -m timeit -n 100000 -s "import test" "test.p2(999983)"
100000 loops, best of 3: 88.1 usec per loop

我在这里错误地使用了 any() 吗?有没有办法使用 any() 编写这个函数,这样它就可以迭代自己?

更新:更大素数的数字

$  python -m timeit -n 1000 -s "import test" "test.p1(9999999999971)"
1000 loops, best of 3: 181 msec per loop

$  python -m timeit -n 1000 -s "import test" "test.p2(9999999999971)"
1000 loops, best of 3: 261 msec per loop

【问题讨论】:

  • docs.python.org/2/library/functions.html#any 它确实和你写的很像。
  • @rightføld 增加 50% 是很小的差别吗?
  • 不,但是
  • 与您的问题没有任何关系,但出于好奇(以及我糟糕的数学技能),您介意向我解释一下为什么您只需要使用xrange(2, int(math.sqrt(n)) + 1) 范围吗?我一直都是xrange(2, n)
  • @IanAuld,如果sqrt(n) 之上的任何x 将除以n,那么另一个因素将是< sqrt(n),到那时你就会找到它。

标签: python


【解决方案1】:

性能差异很小,但它存在的原因是 any 与 for 循环相比,需要构建生成器表达式和额外的函数调用。但是,两者具有相同的行为(快捷方式评估)。

随着输入大小的增加,差异不会减少(我错了),因为您使用的是生成器表达式,并且迭代它需要在其上调用一个方法 (.next()) 和一个额外的堆栈框架。 any 当然是在幕后做的。

for 循环正在迭代 xrange 对象。 any 正在迭代生成器表达式,而生成器表达式本身正在迭代 xrange 对象。

无论哪种方式,请使用生成最易读/可维护的代码。选择其中一个对您正在编写的任何程序的性能影响很小(如果有的话)。

【讨论】:

  • 谢谢。我知道他们有相同的行为,只是想学习内置函数的正确用法,因为我是 Python 新手。但是对于更大的素数,我没有看到差异缩小(我会稍微更新一下这个问题)。即使是 13 位素数,差异仍然在 50% 左右(~180ms vs ~270ms)。我明白你关于可读性的观点,但对于这个特定的练习,我更感兴趣的是了解 any() 的用法。
  • 谢谢。这就说得通了。我不同意它对性能没有任何影响。一种实现似乎始终比另一种慢 50%,因此根据调用此函数的频率,可能存在显着的性能差异。也就是说,您关于生成器表达式的观点对我来说完全有意义。谢谢!
  • 好吧,像往常一样,编写工作、可读的代码,然后配置文件并优化。总是按这个顺序;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-16
  • 1970-01-01
  • 2023-03-18
  • 2021-11-06
  • 2018-05-22
  • 2017-02-07
相关资源
最近更新 更多