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影响

区分CPUIO密集程序
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.数据库层:索引优化、慢查询消除,批量操作减少IONoSQL
3.网络IO:批量操作,pipeline操作减少IO
4.缓存:使用内存数据库redis/memcached
5.异步:asynciocelery
6.并发:gevent/多线程

以上是关于3-5 Python性能剖析与优化,GIL常考题的主要内容,如果未能解决你的问题,请参考以下文章

Python语言基础常考题

4-7 Python数据结构常考题之栈与队列

4-1 Python常用内置算法与数据结构常考题

Python知识点——面试常考题

《高性能MySQL》- 03 服务器性能剖析

4-5 Python数据结构常考题之链表