【问题标题】:Why is Pypy's deque so slow?为什么 Pypy 的双端队列这么慢?
【发布时间】:2012-11-05 10:59:30
【问题描述】:

这是Project Euler Problem 49 的尝试(有点混乱)。

我应该直截了当地说deque 不是一个好选择!我的想法是缩小质数集以测试成员资格会导致循环加速。然而,当我意识到我应该使用 set(而不用担心删除元素)时,我得到了 60 倍的加速。

from collections import deque
from itertools import permutations
from .sieve import sieve_of_erastothenes  # my own implementation of the Sieve of Erastothenes

primes = deque(prime for prime in sieve_of_erastothenes(10000) if prime > 1000 and prime != 1487)  # all four-digit primes except 1487
try:
    while True:
        prime = primes.popleft()  # decrease the length of primes each time to speed up membership test
        for inc in xrange(1,10000 + 1 - (2 * prime)):  # this limit ensures we don't end up with results > 10000
            inc1 = prime + inc
            inc2 = prime + 2*inc

            if inc1 in primes and inc2 in primes:
                primestr = str(prime)
                perms = set(''.join(tup) for tup in permutations(primestr))  # because permutations() returns tuples
                inc1str = str(inc1)
                inc2str = str(inc2)
                if inc1str in perms and inc2str in perms:
                    print primestr + inc1str + inc2str
                    raise IOError  # I chose IOError because it's unlikely to be raised
                                   # by anything else in the block. Exceptions are an easy
                                   # way to break out of nested loops.
except IOError:
    pass

无论如何,在我想使用set 之前,我在 Pypy 中尝试过。我发现结果相当令人惊讶:

$ time python "problem49-deque.py"
296962999629

real    1m3.429s
user    0m49.779s
sys 0m0.335s

$ time pypy-c "problem49-deque.py"
296962999629

real    5m52.736s
user    5m15.608s
sys 0m1.509s

为什么 Pypy 在这段代码上的速度要慢五倍以上?我猜是 Pypy 的 deque 版本是罪魁祸首(因为它在 set 版本上运行得更快),但我不知道为什么会这样。

【问题讨论】:

  • 感谢您提出这个问题!我正要发布一个问题,询问为什么我的代码的双端队列版本比列表版本慢 28%。

标签: python deque pypy


【解决方案1】:

慢的部分是inc1 in primes and inc2 in primes。我会看看为什么 PyPy 这么慢(基本上感谢性能错误报告)。请注意,正如您提到的,代码可以变得非常快(在 PyPy 和 CPython 上)——在这种情况下,只需将 primes 双端队列复制到 for 循环之前的集合中。

【讨论】:

  • +1,但我没有接受答案,因为它还没有回答问题。如果您发现问题所在,请您反馈给我好吗?我很想知道是什么原因造成的。
  • 官方错误跟踪器已移动:bitbucket.org/pypy/pypy/issues/1327(当然,从现在开始,它已经被永远修复了。)
【解决方案2】:

您应该期望双端队列中的成员资格测试(具有 python 性能特征)会很慢,因为列表中的任何成员资格测试都涉及线性扫描。相比之下,set 是针对成员资格测试优化的数据结构。从这个意义上说,这里没有错误。

【讨论】:

  • 我的问题是关于 CPython 的 deque 和 Pypy 的 deque 之间的速度差异。我同意(见问题)set 在这种特殊情况下是正确的数据结构选择,deque 不是。
  • @poorsod 对,但您的问题是“为什么不适当的数据结构会表现不佳”。答案是不合适的,而且这是事先就知道的。 CPython 成员资格测试代码经过高度优化固然好,但 CPython 代码没有经过高度优化也不错,因为这不是适合需要进行许多此类测试的数据结构。
  • 我很好奇 Pypy 的成员资格测试比 CPython 慢 这么多 的确切原因。如果您觉得问题在这一点上不清楚,我会编辑它。
  • @poorsod 并不是说​​不清楚。这是你不能简单地坚持人们只评论你想要限制的问题部分,无论出于何种原因。
  • 我认为@poorsod 的问题是合法的,这是我观看此线程的唯一原因。我明白了,我想他明白了,那套路是要走的。但是,作为对 PyPy 和动态 JIT 实现的演变感兴趣的人,通常可以非常清楚地了解引擎本身,以诊断给定行为为何会出现。这就是真正有趣的地方。我猜他是否应该以这种愿望敲诈一个答案是另一个问题。也许这就是你想要开车回家的全部内容
猜你喜欢
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 2022-01-05
  • 1970-01-01
  • 2021-10-12
相关资源
最近更新 更多