3-5 Python性能剖析与优化,GIL常考题
Posted WinvenChang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3-5 Python性能剖析与优化,GIL常考题相关的知识,希望对你有一定的参考价值。
一、什么是 Cpython GIL
GIL, Global Interpreter Lock
1.Cpython
解释器的内存管理并不是线程安全的
2.保护多线程情况下对 Python
对象的访问
3.Cpython
使用简单的锁机制避免多个线程同时执行字节码
说明:
这样做的缺陷:无法利用cpu
的多核,因为只有一个线程去执行字节码,这对cpu
密集型任务来说,影响会比较大
二、GIL
的影响
限制了程序的多核执行
1.同一个时间只能有一个线程执行字节码
2.CPU
密集程序难以利用多核优势
3.IO
期会释放GIL
,对IO
密集程序影响不大
说明:
cpu
密集是把大量时间花在计算上,IO
密集是把大量时间花在网络传输上。
三、如何规避GIL
影响
区分CPU
和IO
密集程序
1.CPU
密集可以使用多进程+进程池
2.IO
密集使用多线程/协程
3.cython
扩展,可以把python
程序转换成c
程序的扩展
四、GIL
的实现
五、问题:请问这段代码输出?
import threading
n = [0]
def foo():
n[0] = n[0] + 1
n[0] = n[0] + 1
threads = []
for i in range(5000):
t = threading.Thread(target=foo)
threads.append(t)
for t in threads:
t.start()
print(n)
以上代码结果会是 10000
?
运行结果:
说明:
当执行多次时,大部分结果是 10000,少部分出小于 10000。
这是因为这段程序是线程不安全的。当有些线程执行 + 1
操作后,还没保存时,它的结果就被另一个线程覆盖了,所以会出现执行两次 +1
操作,结果有一次 +1
操作丢失了。
六、为什么有了GIL
还要关注线程安全
Python
中什么操作才是原子的?一步到位执行完
1.一个操作如果是一个字节码指令可以完成就是原子的
2.原子的是可以保证线程安全的
3.使用dis
操作来分析字节码
看以下代码:
原子操作是线程安全的:
import dis
def update_list(l):
l[0] = 1 # 原子操作,不用担心线程安全问题
dis.dis(update_list)
"""
6 0 LOAD_CONST 1 (1)
3 LOAD_FAST 0 (l)
6 LOAD_CONST 2 (0)
9 STORE_SUBSCR # 单字节码操作,线程安全
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
"""
非原子操作不是线程安全的
import dis
def incr_list(l):
l[0] += 1 # 危险!!!不是原子操作
dis.dis(incr_list)
"""
21 0 LOAD_FAST 0 (l)
3 LOAD_CONST 2 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 (1)
13 INPLACE_ADD # 需要多个字节码操作,有可能在线程执行过程中切到其他线程
14 ROT_THREE
15 STORE_SUBSCR
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
"""
如下分析图示:
如何保证线程安全:通过加锁实现
给前面的代码加锁
import threading
lock = threading.Lock() # 加锁
n = [0]
def foo():
with lock: # 加锁
n[0] = n[0] + 1
n[0] = n[0] + 1
threads = []
for i in range(5000):
t = threading.Thread(target=foo)
threads.append(t)
for t in threads:
t.start()
print(n)
注意:加锁对程序性能有一定的影响,但加锁是解决线程安全的常见方式。
七、如何剖析程序性能
使用各种profile
工具(内置或第三方)
1.二八定律,大部分时间耗时在少量代码上
2.内置的profile
/cprofile
等工具
3.使用pyflame
(uber
开源)的火焰图工具
八、服务端性能优化措施
Web
应用一般语言不会成为瓶颈
1.数据结构与算法优化
2.数据库层:索引优化、慢查询消除,批量操作减少IO
,NoSQL
3.网络IO
:批量操作,pipeline
操作减少IO
4.缓存:使用内存数据库redis
/memcached
5.异步:asyncio
,celery
6.并发:gevent
/多线程
以上是关于3-5 Python性能剖析与优化,GIL常考题的主要内容,如果未能解决你的问题,请参考以下文章