使用cProfile识别未明确的瓶颈

时间:2017-11-08 21:33:14

标签: python

您能帮助确定此代码的瓶颈吗?我正在解决项目Euler的问题#7,并且我无法理解为什么这个解决方案需要这么长时间(30s)。我知道有更好的解决方案,我只想更多地了解为什么会这样,特别是那么糟糕。

def primes(n):
    primes = set([2])
    count = 1
    i = 1
    while count < n:
        i += 2
        if not any([i % num == 0 for num in primes]):
            primes.add(i)
            count += 1
    print i

cProfile.run("primes(10001)") #slow! 30s

个人资料如下:

62374 function calls in 34.605 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   34.605   34.605 <string>:1(<module>)
        1   34.273   34.273   34.605   34.605 problem_7.py:8(primes)
    52371    0.328    0.000    0.328    0.000 {any}
    10000    0.004    0.000    0.004    0.000 {method 'add' of 'set' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

1 个答案:

答案 0 :(得分:0)

我实施了一些调整来帮助解决问题。请参阅下面的评论和结果。在所有情况下,我都将累加器从名为primes(隐藏其函数名称)改为名为ps。我没有测试,看看这是否改善了性能,我只是讨厌阴影名称:o)

# Your original code
def prime_orig(n):
    ps = set([2])
    count = 1
    i = 1
    while count < n:
        i += 2
        if not any([i % num == 0 for num in ps]):
            ps.add(i)
            count += 1

# replace the set accum with a list, per @Sheshnath's comment
def prime_list(n):
    ps = [2]
    count = 1
    i = 1
    while count < n:
        i += 2
        if not any([i % num == 0 for num in ps]):
            ps.append(i)
            count += 1

# replace the listcomp with a genexp
def prime_genexp(n):
    ps = set([2])
    count = 1
    i = 1
    while count < n:
        i += 2
        if not any(i % num == 0 for num in ps):
            ps.add(i)
            count += 1

# both optimizations at once
def prime_genexp_list(n):
    ps = [2]
    count = 1
    i = 1
    while count < n:
        i += 2
        if not any(i % num == 0 for num in ps):
            ps.append(i)
            count += 1

结果:

cProfile.run('prime_orig(10001)')

         114746 function calls in 27.283 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.701    0.701   27.283   27.283 <ipython-input-2-3059f1e23ab4>:1(prime_orig)
    52371   26.330    0.001   26.330    0.001 <ipython-input-2-3059f1e23ab4>:7(<listcomp>)
        1    0.000    0.000   27.283   27.283 <string>:1(<module>)
    52371    0.250    0.000    0.250    0.000 {built-in method builtins.any}
        1    0.000    0.000   27.283   27.283 {built-in method builtins.exec}
    10000    0.003    0.000    0.003    0.000 {method 'add' of 'set' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

cProfile.run('prime_list(10001)')

         114746 function calls in 24.523 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.666    0.666   24.523   24.523 <ipython-input-2-3059f1e23ab4>:11(prime_list)
    52371   23.625    0.000   23.625    0.000 <ipython-input-2-3059f1e23ab4>:17(<listcomp>)
        1    0.000    0.000   24.523   24.523 <string>:1(<module>)
    52371    0.231    0.000    0.231    0.000 {built-in method builtins.any}
        1    0.000    0.000   24.523   24.523 {built-in method builtins.exec}
    10000    0.001    0.000    0.001    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

cProfile.run('prime_genexp(10001)')

         50627376 function calls in 10.577 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.040    0.040   10.577   10.577 <ipython-input-2-3059f1e23ab4>:21(prime_genexp)
 50565001    7.060    0.000    7.060    0.000 <ipython-input-2-3059f1e23ab4>:27(<genexpr>)
        1    0.000    0.000   10.577   10.577 <string>:1(<module>)
    52371    3.475    0.000   10.530    0.000 {built-in method builtins.any}
        1    0.000    0.000   10.577   10.577 {built-in method builtins.exec}
    10000    0.002    0.000    0.002    0.000 {method 'add' of 'set' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

cProfile.run('prime_genexp_list(10001)')

         50400891 function calls in 9.781 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.040    0.040    9.781    9.781 <ipython-input-2-3059f1e23ab4>:31(prime_genexp_list)
 50338516    6.272    0.000    6.272    0.000 <ipython-input-2-3059f1e23ab4>:37(<genexpr>)
        1    0.000    0.000    9.781    9.781 <string>:1(<module>)
    52371    3.468    0.000    9.735    0.000 {built-in method builtins.any}
        1    0.000    0.000    9.781    9.781 {built-in method builtins.exec}
    10000    0.001    0.000    0.001    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}