<p>在Python优化方面,除了使用PyPy(在代码没有任何变化的情况下提高了速度)之外,还可以使用pypyy的<a href="http://doc.pypy.org/en/release-1.9/translation.html" rel="noreferrer">translation toolchain</a>来编译与RPython兼容的版本,或者<a href="http://docs.cython.org/src/quickstart/overview.html" rel="noreferrer">Cython</a>来构建扩展模块,这两个模块在我的测试中都比C版本快,使用Cython模块的速度几乎是前者的两倍。作为参考,我还包括C和PyPy基准测试结果:</p>
<p><em>C(用<code>gcc -O3 -lm</code></em>编译)</p>
<pre><code>% time ./euler12-c
842161320
./euler12-c 11.95s
user 0.00s
system 99%
cpu 11.959 total
</code></pre>
<p><em>PyPy 1.5</em></p>
<pre><code>% time pypy euler12.py
842161320
pypy euler12.py
16.44s user
0.01s system
99% cpu 16.449 total
</code></pre>
<p><em>RPython(使用最新的PyPy版本,<code>c2f583445aee</code>)</em></p>
<pre><code>% time ./euler12-rpython-c
842161320
./euler12-rpy-c
10.54s user 0.00s
system 99%
cpu 10.540 total
</code></pre>
<p><em>Cython 0.15</em></p>
<pre><code>% time python euler12-cython.py
842161320
python euler12-cython.py
6.27s user 0.00s
system 99%
cpu 6.274 total
</code></pre>
<p>RPython版本有几个关键的变化。要转换成独立程序,需要定义<code>target</code>,在本例中是<code>main</code>函数。它应该接受<code>sys.argv</code>,因为它是唯一的参数,并且需要返回一个int。您可以通过使用translate.py来翻译它,<code>% translate.py euler12-rpython.py</code>,它将转换为C并为您编译它。</p>
<pre><code># euler12-rpython.py
import math, sys
def factorCount(n):
square = math.sqrt(n)
isquare = int(square)
count = -1 if isquare == square else 0
for candidate in xrange(1, isquare + 1):
if not n % candidate: count += 2
return count
def main(argv):
triangle = 1
index = 1
while factorCount(triangle) < 1001:
index += 1
triangle += index
print triangle
return 0
if __name__ == '__main__':
main(sys.argv)
def target(*args):
return main, None
</code></pre>
<p>Cython版本被重写为一个扩展模块<code>_euler12.pyx</code>,我从一个普通的python文件导入并调用它。<code>_euler12.pyx</code>本质上与您的版本相同,并带有一些附加的静态类型声明。py使用<code>python setup.py build_ext --inplace</code>具有构建扩展的标准样板。</p>
<pre><code># _euler12.pyx
from libc.math cimport sqrt
cdef int factorCount(int n):
cdef int candidate, isquare, count
cdef double square
square = sqrt(n)
isquare = int(square)
count = -1 if isquare == square else 0
for candidate in range(1, isquare + 1):
if not n % candidate: count += 2
return count
cpdef main():
cdef int triangle = 1, index = 1
while factorCount(triangle) < 1001:
index += 1
triangle += index
print triangle
# euler12-cython.py
import _euler12
_euler12.main()
# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("_euler12", ["_euler12.pyx"])]
setup(
name = 'Euler12-Cython',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
</code></pre>
<p>老实说,我对RPython和Cython都没有什么经验,对结果感到惊喜。如果您使用的是CPython,那么在Cython扩展模块中编写CPU密集型代码似乎是优化程序的一种非常简单的方法。</p>