GIL全局解释器锁与协程
一、GIL全局解释器锁
在同一个进程下开启的多线程,同一时刻只能有一个线程执行,因为Cpython的内存管理不是线程安全
GIL全局解释器锁,本质上就是一把互斥锁,保证数据安全
1 import time 2 from threading import Thread 3 4 n = 100 5 6 7 def task(): 8 global n 9 m = n 10 time.sleep(3) 11 n = m - 1 12 13 14 if __name__ == '__main__': 15 list1 = [] 16 for line in range(10): 17 t = Thread(target=task) 18 t.start() 19 list1.append(t) 20 21 for t in list1: 22 t.join() 23 24 print(n)
在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势
优点:
保证数据的安全性
缺点:
单个进程下,开启多个线程,牺牲执行效率,无法实现并行,只能实现并发
不同情况下使用多进程或者多线程比较
IO密集型下使用多线程.
计算密集型下使用多进程
1 # 计算密集型任务 2 def task1(): 3 # 计算1000000次 += 1 4 i = 10 5 for line in range(10000000): 6 i += 1 7 8 9 # IO密集型任务· 10 def task2(): 11 time.sleep(3) 12 13 14 if __name__ == '__main__': 15 # 1、测试多进程: 16 # 测试计算密集型 17 start_time = time.time() 18 list1 = [] 19 for line in range(6): 20 p = Process(target=task1) 21 p.start() 22 list1.append(p) 23 for p in list1: 24 p.join() 25 end_time = time.time() 26 # 消耗时间: 0.9640259742736816 27 print(f'计算密集型消耗时间: {end_time - start_time}') 28 29 # 测试IO密集型 30 start_time = time.time() 31 list1 = [] 32 for line in range(6): 33 p = Process(target=task2) 34 p.start() 35 list1.append(p) 36 for p in list1: 37 p.join() 38 end_time = time.time() 39 # 消耗时间: 3.1492795944213867 40 print(f'IO密集型消耗时间: {end_time - start_time}') 41 42 43 # 2、测试多线程: 44 # 测试计算密集型 45 start_time = time.time() 46 list1 = [] 47 for line in range(6): 48 p = Thread(target=task1) 49 p.start() 50 list1.append(p) 51 for p in list1: 52 p.join() 53 end_time = time.time() 54 # 消耗时间: 3.3614895343780518 55 print(f'计算密集型消耗时间: {end_time - start_time}') 56 57 # 测试IO密集型 58 start_time = time.time() 59 list1 = [] 60 for line in range(6): 61 p = Thread(target=task2) 62 p.start() 63 list1.append(p) 64 for p in list1: 65 p.join() 66 end_time = time.time() 67 # 消耗时间: 3.002037763595581 68 print(f'IO密集型消耗时间: {end_time - start_time}')
二、协程
进程、线程、协程:
- 进程: 资源单位
- 线程: 执行单位
- 协程: 单线程下实现并发
在IO密集型的情况下,使用协程能提高最高效率
协程作用:
手动实现 “遇到IO切换 + 保存状态” 来欺骗操作系统,让操作系统误以为没有IO操作,将CPU的执行权限给你
1 from gevent import monkey # 猴子补丁 2 monkey.patch_all() # 监听所有的任务是否有IO操作 3 from gevent import spawn # spawn(任务) 4 from gevent import joinall 5 import time 6 7 def task1(): 8 print('start from task1...') 9 time.sleep(1) 10 print('end from task1...') 11 12 def task2(): 13 print('start from task2...') 14 time.sleep(3) 15 print('end from task2...') 16 17 def task3(): 18 print('start from task3...') 19 time.sleep(5) 20 print('end from task3...') 21 22 23 if __name__ == '__main__': 24 25 start_time = time.time() 26 sp1 = spawn(task1) 27 sp2 = spawn(task2) 28 sp3 = spawn(task3) 29 # sp1.start() 30 # sp2.start() 31 # sp3.start() 32 # sp1.join() 33 # sp2.join() 34 # sp3.join() 35 joinall([sp1, sp2, sp3]) 36 37 end_time = time.time() 38 39 print(f'消耗时间: {end_time - start_time}')