Several methods to improve python performance

WBOY
Release: 2016-08-04 08:55:45
Original
1564 people have browsed it

Some solutions to improve python performance.

1. Function call optimization (space span, avoid memory access)

The core point of program optimization is to minimize the span of operations, including the span of code execution time and the span of memory space.

1. Big data summation, use sum

a = range(100000)
%timeit -n 10 sum(a)
10 loops, best of 3: 3.15 ms per loop
%%timeit
  ...: s = 0
  ...: for i in a:
  ...:  s += i
  ...:
100 loops, best of 3: 6.93 ms per loop
Copy after login

2. Sum small data, avoid using sum

%timeit -n 1000 s = a + b + c + d + e + f + g + h + i + j + k # 数据量较小时直接累加更快
1000 loops, best of 3: 571 ns per loop
%timeit -n 1000 s = sum([a,b,c,d,e,f,g,h,i,j,k]) # 小数据量调用 sum 函数,空间效率降低
1000 loops, best of 3: 669 ns per loop
Copy after login

Conclusion: The sum of big data is highly efficient, and the sum of small data is highly efficient in direct accumulation.

2. For loop optimization to get elements (use stack or register to avoid memory access)

for lst in [(1, 2, 3), (4, 5, 6)]: # lst 索引需要额外开销
  pass
Copy after login

 The use of indexes should be avoided as much as possible.

for a, b, c in [(1, 2, 3), (4, 5, 6)]: # better
  pass
Copy after login

Equivalent to directly assigning a value to each element.

def force():
 lst = range(4)
 for a1 in [1, 2]:
   for a2 in lst:
     for a3 in lst:
       for b1 in lst:
         for b2 in lst:
           for b3 in lst:
             for c1 in lst:
               for c2 in lst:
                 for c3 in lst:
                   for d1 in lst:
                     yield (a1, a2, a3, b1, b2, b3, c1, c2, c3, d1)
                      
%%timeit -n 10
for t in force():
  sum([t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9]])
10 loops, best of 3: 465 ms per loop
%%timeit -n 10
for a1, a2, a3, b1, b2, b3, c1, c2, c3, d1 in force():
  sum([a1, a2, a3, b1, b2, b3, c1, c2, c3, d1])
10 loops, best of 3: 360 ms per loop
Copy after login

3. Generator optimization (lookup table instead of operation)

def force(start, end): # 用于密码暴力破解程序
  for i in range(start, end):
    now = i
    sublst = []
    for j in range(10):
      sublst.append(i % 10) # 除法运算开销较大,比乘法大
      i //= 10
    sublst.reverse()
    yield(tuple(sublst), now)
Copy after login

def force(): # better
 lst = range(5)
 for a1 in [1]:
   for a2 in lst:
     for a3 in lst:
       for b1 in lst:
         for b2 in lst:
           for b3 in lst:
             for c1 in lst:
               for c2 in lst:
                 for c3 in lst:
                   for d1 in lst:
                     yield (a1, a2, a3, b1, b2, b3, c1, c2, c3, d1)
  
Copy after login

r0 = [1, 2] # 可读性与灵活性
r1 = range(10)
r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = r1
force = ((a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
      for a0 in r0 for a1 in r1 for a2 in r2 for a3 in r3 for a4 in r4
      for a5 in r5 for a6 in r6 for a7 in r7 for a8 in r8 for a9 in r9)
Copy after login

4. Power operation optimization (pow (x, y, z))

def isprime(n):
  if n & 1 == 0:
    return False
  k, q = find_kq(n)
  a = randint(1, n - 1)
  if pow(a, q, n) == 1: # 比使用 a ** q % n 运算优化数倍
    return True
  for j in range(k):
    if pow(a, pow(2, j) * q, n) == n - 1: # a **((2 ** j) * q) % n
      return True
  return False
Copy after login

Conclusion: pow(x,y,z) is better than x**y%z.

5. Division operation optimization

In [1]: from random import getrandbits
 
In [2]: x = getrandbits(4096)
 
In [3]: y = getrandbits(2048)
 
In [4]: %timeit -n 10000 q, r = divmod(x, y)
10000 loops, best of 3: 10.7 us per loop
 
In [5]: %timeit -n 10000 q, r = x//y, x % y
10000 loops, best of 3: 21.2 us per loop
Copy after login

Conclusion: divmod is better than // and %.

6. Time complexity of optimization algorithm 

The time complexity of the algorithm has the greatest impact on the execution efficiency of the program. In python, you can choose an appropriate data structure to optimize the time complexity. For example, the time complexity of searching for a certain element in list and set is O(n) and O( respectively. 1). Different scenarios have different optimization methods. Generally speaking, there are generally ideas such as divide and conquer, branch and bound, and greedy dynamic programming.

7. Reasonable use of copy and deepcopy 

For objects of data structures such as dict and list, direct assignment uses reference. In some cases, you need to copy the entire object. In this case, you can use copy and deepcopy in the copy package. The difference between these two functions is that deepcopy copies recursively. Efficiency is different:

In [23]: import copy
In [24]: %timeit -n 10 copy.copy(a)
10 loops, best of 3: 606 ns per loop
In [25]: %timeit -n 10 copy.deepcopy(a)
10 loops, best of 3: 1.17 us per loop
Copy after login

The -n after timeit indicates the number of runs. The last two lines correspond to the output of the two timeit, the same below. It can be seen that the latter is an order of magnitude slower.

An example about copy:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
Copy after login

What happens is this, [[]] is a one-element list containing an empty list, so all three elements of [[]] * 3 are (point to) this empty list. Modifying any element of lists modifies the list. The modification efficiency is high.

8. Use dict or set to find elements

Python dictionaries and sets are implemented using hash tables (similar to the c++ standard library unordered_map), and the time complexity of finding elements is O(1).

In [1]: r = range(10**7)
In [2]: s = set(r) # 占用 588MB 内存
In [3]: d = dict((i, 1) for i in r) # 占用 716MB 内存
In [4]: %timeit -n 10000 (10**7) - 1 in r
10000 loops, best of 3: 291 ns per loop
In [5]: %timeit -n 10000 (10**7) - 1 in s
10000 loops, best of 3: 121 ns per loop
In [6]: %timeit -n 10000 (10**7) - 1 in d
10000 loops, best of 3: 111 ns per loop
Copy after login

Conclusion: set has the smallest memory footprint and dict has the shortest running time.

9. Reasonable use (generator) and yield (save memory)

In [1]: %timeit -n 10 a = (i for i in range(10**7)) # 生成器通常遍历更高效
10 loops, best of 3: 933 ns per loop
In [2]: %timeit -n 10 a = [i for i in range(10**7)]
10 loops, best of 3: 916 ms per loop
In [1]: %timeit -n 10 for x in (i for i in range(10**7)): pass
10 loops, best of 3: 749 ms per loop
In [2]: %timeit -n 10 for x in [i for i in range(10**7)]: pass
10 loops, best of 3: 1.05 s per loop
Copy after login

Conclusion: Try to use generators to traverse.

The above are some solutions to improve python performance. We will continue to add more in the future. You can take a look if you need them.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template