程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

! These 15 tips directly take your Python performance off

編輯:Python

This is my participation 2022 For the first time, the third challenge is 8 God , Check out the activity details :2022 For the first time, it's a challenge

Preface

Python What has been criticized by everyone is the slow execution speed , But there's no denying it Python It is still a sharp weapon in our study and work . therefore , We are right. Python What is it? “ Love and hate ”.

This article summarizes some small  tips  Help to improve Python Execution speed 、 Optimize performance . All of the following techniques have been verified by me , It's safe to eat .

Come to the conclusion first :

  1. Use map() Function mapping
  2. Use set() Find the intersection
  3. Use sort() or sorted() Sort
  4. Use collections.Counter() Count
  5. Use list derivation
  6. Use join() Connection string
  7. Use x, y = y, x Exchange variables
  8. Use while 1 replace while True
  9. Use decorator cache
  10. Reduce the dot operator (.) Use
  11. Use for Circulation replaces while loop
  12. Use Numba.jit Accelerate Computing
  13. Use Numpy Vectorized array
  14. Use in Check list members
  15. Use itertools Library iteration

How to measure the execution time of the program

About Python How to accurately measure the execution time of the program , The problem seems simple, but it's actually very complicated , Because the execution time of the program is affected by many factors , For example, operating system 、Python Version and related hardware (CPU performance 、 Memory read and write speed ) etc. . When running the same version of the language on the same computer , The above factors are certain , But the sleep time of the program is still changing , And other programs running on the computer will also interfere with the experiment , So strictly speaking, this is 《 The experiment cannot be repeated 》.

The two representative libraries I learned about timing are time and timeit.

among ,time In the library time()perf_counter() as well as process_time() Three functions can be used to time ( In seconds ), suffix _ns Time in nanoseconds ( since Python3.7 beginning ). Before that clock() function , But in Python3.3 Then it was removed . The differences between the above three are as follows :

  • time() The accuracy is relatively not that high , And affected by the system , Suitable for representing date and time or timing of large programs .
  • perf_counter() Suitable for smaller program testing , Calculation sleep() Time .
  • process_time() Suitable for smaller program testing , Don't count sleep() Time .

And time Coop ,timeit  There are two advantages :

  • timeit  According to your operating system and Python Select the best timer for the version .
  • timeit  Garbage collection is temporarily disabled during timing .

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)  Parameter description :

  • stmt='pass': Statements or functions that need timing .
  • setup='pass': perform stmt Code to run before . Usually , It is used to import some modules or declare some necessary variables .
  • timer=<default timer>: Timer function , The default is time.perf_counter().
  • number=1000000: The number of times the timed statement was executed , Default is one million times .
  • globals=None: Specifies the namespace in which the code is executed .

All timing in this paper adopts timeit Method , And the default execution times are one million times .

Why a million times ? Because our test program is very short , If you don't do it so many times , There is no difference at all .

Text

1. Use map() Function mapping

Exp1: Convert lowercase letters to uppercase letters in the string array .

The test array is oldlist = ['life', 'is', 'short', 'i', 'choose', 'python'].

  • Method 1
newlist = []
for word in oldlist:
newlist.append(word.upper())
Copy code 
  • Method 2
list(map(str.upper, oldlist))
Copy code 

Method one takes time  0.5267724000000005s, Method two takes time  0.41462569999999843s, Performance improvement  21.29% 

2. Use set() Find the intersection

Exp2: Two, please list Intersection .

Test array :a = [1,2,3,4,5],b = [2,4,6,8,10].

  • Method 1
overlaps = []
for x in a:
for y in b:
if x == y:
overlaps.append(x)
Copy code 
  • Method 2
list(set(a) & set(b))
Copy code 

Method one takes time  0.9507264000000006s, Method two takes time  0.6148200999999993s, Performance improvement  35.33% 

About set() The grammar of :|&- Respectively represent the union set 、 intersection 、 Difference set .

3. Use sort() or sorted() Sort

We can sort the sequence in many ways , But in fact, the method of writing sorting algorithm by yourself is not worth the loss . Because of the built-in  sort() or  sorted()  The method is good enough , And use parameters key Different functions can be realized , Very flexible . The difference between them is sort() Methods are defined only in list in , and sorted() The global method is effective for all iterative sequences .

Exp3: Use fast platoon and..., respectively sort() Method to sort the same list .

Test array :lists = [2,1,4,3,0].

  • Method 1
def quick_sort(lists,i,j):
if i >= j:
return list
pivot = lists[i]
low = i
high = j
while i < j:
while i < j and lists[j] >= pivot:
j -= 1
lists[i]=lists[j]
while i < j and lists[i] <=pivot:
i += 1
lists[j]=lists[i]
lists[j] = pivot
quick_sort(lists,low,i-1)
quick_sort(lists,i+1,high)
return lists
Copy code 
  • Method 2
lists.sort()
Copy code 

Method one takes time  2.4796975000000003s, Method two takes time  0.05551999999999424s, Performance improvement  97.76% 

By the way ,sorted() The method is time consuming  0.1339823999987857s.

It can be seen that ,sort() As list The exclusive sorting method is still very strong ,sorted() Although a little slower than the former , But the victory is in it “ No picky eaters ”, It works for all iteratable sequences .

Expand : How to define sort() or sorted() Methodical key

  1. adopt lambda Definition
# Student :( full name , achievement , Age )
students = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]
students.sort(key = lambda student: student[0]) # Sort by name
sorted(students, key = lambda student: student[0])
Copy code 
  1. adopt operator Definition
import operator
students = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]
students.sort(key=operator.itemgetter(0))
sorted(students, key = operator.itemgetter(1, 0)) # Sort your grades first , Then sort the names
Copy code 

operator Of itemgetter() Suitable for ordinary array sorting ,attrgetter() Applicable to object array sorting

  1. adopt cmp_to_key() Definition , Most flexible
import functools
def cmp(a,b):
if a[1] != b[1]:
return -1 if a[1] < b[1] else 1 # First sort them in ascending order
elif a[0] != b[0]:
return -1 if a[0] < b[0] else 1 # Same grades , Sort by name in ascending order
else:
return -1 if a[2] > b[2] else 1 # The grades and names are the same , Sort by age
students = [('john', 'A', 15),('john', 'A', 14),('jane', 'B', 12),('dave', 'B', 10)]
sorted(students, key = functools.cmp_to_key(cmp))
Copy code 

4. Use collections.Counter() Count

Exp4: Count the number of occurrences of each character in the string .

Test array :sentence='life is short, i choose python'.

  • Method 1
counts = {}
for char in sentence:
counts[char] = counts.get(char, 0) + 1
Copy code 
  • Method 2
from collections import Counter
Counter(sentence)
Copy code 

Method one takes time  2.8105250000000055s, Method two takes time  1.6317423000000062s, Performance improvement  41.94% 

5. Use list derivation

The list of deduction (list comprehension) short . In small code snippets , It may not make much difference . But in large-scale development , It can save some time .

Exp5: Square the odd numbers in the list , Even numbers don't change .

Test array :oldlist = range(10).

  • Method 1
newlist = []
for x in oldlist:
if x % 2 == 1:
newlist.append(x**2)
Copy code 
  • Method 2
[x**2 for x in oldlist if x%2 == 1]
Copy code 

Method one takes time  1.5342976000000021s, Method two takes time  1.4181957999999923s, Performance improvement  7.57% 

6. Use  join()  Connection string

Most people are used to using + To connect strings . But in fact , This method is very inefficient . because ,+ In each step of the operation, a new string is created and the old string is copied . A better way is to use  join()  To connect strings . Other operations on strings , Also try to use built-in functions , Such as isalpha()isdigit()startswith()endswith() etc. .

Exp6: Connect the elements in the string list .

Test array :oldlist = ['life', 'is', 'short', 'i', 'choose', 'python'].

  • Method 1
sentence = ""
for word in oldlist:
sentence += word
Copy code 
  • Method 2
"".join(oldlist)
Copy code 

Method one takes time  0.27489080000000854s, Method two takes time  0.08166570000000206s, Performance improvement  70.29% 

join There is also a very comfortable point , That is, it can specify the separator of the connection , for instance

oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']
sentence = "//".join(oldlist)
print(sentence)
Copy code 

life//is//short//i//choose//python

7. Use x, y = y, x Exchange variables

Exp6: In exchange for x,y Value .

Test data :x, y = 100, 200.

  • Method 1
temp = x
x = y
y = temp
Copy code 
  • Method 2
x, y = y, x
Copy code 

Method one takes time  0.027853900000010867s, Method two takes time  0.02398730000000171s, Performance improvement  13.88% 

8. Use while 1 replace while True

When you don't know the exact number of cycles , The conventional method is to use while True Make an infinite loop , Determine whether the loop termination condition is met in the code block . Although there is no problem doing so , but while 1 The execution speed ratio of while True faster . Because it is a numerical conversion , Output can be generated faster .

Exp8: Use them separately while 1 and while True loop 100 Time .

  • Method 1
i = 0
while True:
i += 1
if i > 100:
break
Copy code 
  • Method 2
i = 0
while 1:
i += 1
if i > 100:
break
Copy code 

Method one takes time  3.679268300000004s, Method two takes time  3.607847499999991s, Performance improvement 1.94% 

9. Use decorator cache

Storing files in a cache helps to quickly restore functionality .Python Support decorator cache , The cache maintains a specific type of cache in memory , To achieve the best software driven speed . We use lru_cache Decorator to provide caching for Fibonacci functions , In the use of fibonacci When recursive functions , There's a lot of double counting , for example fibonacci(1)fibonacci(2) It ran many times . And in use lru_cache after , All double counting will be performed only once , So as to greatly improve the execution efficiency of the program .

Exp9: Find the Fibonacci sequence .

Test data :fibonacci(7).

  • Method 1
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
Copy code 
  • Method 2
import functools
@functools.lru_cache(maxsize=128)
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
Copy code 

Method one takes time  3.955014900000009s, Method two takes time  0.05077979999998661s, Performance improvement  98.72% 

matters needing attention :

  • Caching is based on parameters as keys , That is to say, when the parameters remain unchanged , By lru_cache The decorated function will only execute once .
  • All parameters must be hashable , for example list Cannot be used as lru_cache The parameters of the decorated function .
import functools
@functools.lru_cache(maxsize=100)
def demo(a, b):
print(' I was executed ')
return a + b
if __name__ == '__main__':
demo(1, 2)
demo(1, 2)
Copy code 

I was executed ( Twice demo(1, 2), But only output once

from functools import lru_cache
@lru_cache(maxsize=100)
def list_sum(nums: list):
return sum(nums)
if __name__ == '__main__':
list_sum([1, 2, 3, 4, 5])
Copy code 

TypeError: unhashable type: 'list'

functools.lru_cache(maxsize=128, typed=False) Two optional parameters of :

  • maxsize Represents the memory usage value of the cache , After exceeding this value , The result will be released , Then cache the new calculation results , Its value should be set to 2 The power of .
  • typed if True, The results of different parameter types will be saved separately .

10. Reduce the dot operator (.) Use

Dot operator (.) The property or method used to access the object , This will cause the program to use __getattribute__() and __getattr__() Look up the dictionary , This brings unnecessary expenses . Pay special attention to , In the cycle , It is also necessary to reduce the use of point operators , It should be moved out of the loop .

This suggests that we should try to use from ... import ... This way to guide the package , Instead of using the dot operator to get... When a method needs to be used . It's not just dot operators , We try to move many other unnecessary operations out of the loop .

Exp10: Convert lowercase letters to uppercase letters in the string array .

The test array is oldlist = ['life', 'is', 'short', 'i', 'choose', 'python'].

  • Method 1
newlist = []
for word in oldlist:
newlist.append(str.upper(word))
Copy code 
  • Method 2
newlist = []
upper = str.upper
for word in oldlist:
newlist.append(upper(word))
Copy code 

Method one takes time  0.7235491999999795s, Method two takes time  0.5475435999999831s, Performance improvement  24.33% 

11. Use for Circulation replaces while loop

When we know exactly how many times to cycle , Use for Cycle ratio use while Better cycle .

Exp12: Use for and while Separate cycles 100 Time .

  • Method 1
i = 0
while i < 100:
i += 1
Copy code 
  • Method 2
for _ in range(100):
pass
Copy code 

Method one takes time  3.894683299999997s, Method two takes time  1.0198077999999953s, Performance improvement 73.82% 

12. Use Numba.jit Accelerate Computing

Numba Can be Python Function encoding and decoding is executed for machine code , Greatly improve the speed of code execution , Even close C or FORTRAN The speed of . It can match Numpy In combination with , stay for It can significantly improve the execution efficiency when there are a lot of calculations in the loop .

Exp12: Seek from 1 Add to 100 And .

  • Method 1
def my_sum(n):
x = 0
for i in range(1, n+1):
x += i
return x
Copy code 
  • Method 2
from numba import jit
@jit(nopython=True)
def numba_sum(n):
x = 0
for i in range(1, n+1):
x += i
return x
Copy code 

Method one takes time  3.7199997000000167s, Method two takes time  0.23769430000001535s, Performance improvement  93.61% 

13. Use Numpy Vectorized array

Vectorization is NumPy A powerful feature of , The operation can be expressed as taking place on the entire array rather than on individual elements . This method of replacing explicit loops with array expressions is often called vectorization .

stay Python When looping through an array or any data structure , It will involve a lot of expenses .NumPy Vectorization in delegates internal loops to highly optimized C and Fortran function , So that Python Code is faster .

Exp13: Two sequences of the same length are multiplied element by element .

Test array :a = [1,2,3,4,5], b = [2,4,6,8,10]

  • Method 1
[a[i]*b[i] for i in range(len(a))]
Copy code 
  • Method 2
import numpy as np
a = np.array([1,2,3,4,5])
b = np.array([2,4,6,8,10])
a*b
Copy code 

Method one takes time  0.6706845000000214s, Method two takes time  0.3070132000000001s, Performance improvement  54.22% 

14. Use in Check list members

To check whether a member is included in the list , Usually use in Keywords faster .

Exp14: Check whether the list contains a member .

Test array :lists = ['life', 'is', 'short', 'i', 'choose', 'python']

  • Method 1
def check_member(target, lists):
for member in lists:
if member == target:
return True
return False
Copy code 
  • Method 2
if target in lists:
pass
Copy code 

Method one takes time  0.16038449999999216s, Method two takes time  0.04139250000000061s, Performance improvement  74.19% 

15. Use itertools Library iteration

itertools Is a module used to operate iterators , Its functions can be divided into three categories : Infinite iterator 、 Finite iterator 、 Combined iterators .

Exp15: Returns the full arrangement of the list .

Test array :["Alice", "Bob", "Carol"]

  • Method 1
def permutations(lst):
if len(lst) == 1 or len(lst) == 0:
return [lst]
result = []
for i in lst:
temp_lst = lst[:]
temp_lst.remove(i)
temp = permutations(temp_lst)
for j in temp:
j.insert(0, i)
result.append(j)
return result
Copy code 
  • Method 2
import itertools
itertools.permutations(["Alice", "Bob", "Carol"])
Copy code 

Method one takes time  3.867292899999484s, Method two takes time  0.3875405000007959s, Performance improvement  89.98% 

Expand itertools Detailed explanation of the library : Click on this link

Conclusion

According to the test data above , I drew the following picture of the experimental results , You can more intuitively see the performance differences brought by different methods .

As you can see from the diagram , The performance increase brought by most techniques is still considerable , But there are also a few skills that have a small increase ( For example, number 5、7、8, among , The first 8 There is little difference between the two methods ).

Sum up , I think it's actually the following two principles :

1. Try to use built-in library functions

The built-in library functions are written by professional developers and have been tested for many times , The bottom layer of many library functions is C Language development . therefore , These functions are generally very efficient ( such as sort()join() etc. ), It's hard to write your own methods beyond them , You might as well save your time , Don't make wheels again , Besides, the wheels you make may be worse . therefore , If the function already exists in the function library , Just use it .

2. Try to use good third-party libraries

There are many excellent third-party libraries , Their bottom layer may be C and Fortran To achieve , A library like this will never suffer a loss when used , For example, as mentioned above Numpy and Numba, The improvements they bring are amazing . There are many libraries like this , such as Cython、PyPy etc. , I'm just throwing a brick at you .

In fact, speed up Python There are many ways to speed up code execution , such as Avoid using global variables Use the latest version Use the right data structure utilize if The inertia of conditions wait , I won't cite one by one here . These methods need us to practice in person before we can have a deep feeling and understanding , But the most fundamental way is to keep our passion for programming and the pursuit of best practices , This is how we can constantly break through ourselves 、 The inexhaustible power source of climbing the peak !

️ Thank you for your

Thank you for seeing this , If you think this is going to help you :

  1. Like it and support it , So that more people can see the content .

  2. Welcome to share your thoughts with me in the message area , You are also welcome to record your thinking process in the message area .

  3. If you are interested, you can also read some of my previous articles :


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved