GIL本质是一把互斥锁,至关于执行权限,每一个进程内都会存在一把GIL同一进程内的多线程,必须抢到GIL以后才能使用Cpython解释器来执行本身的代码,即同一进程下的多个线程没法实现并行,但能够实现并发python
Cpython解释器下想实现并行能够开启多个进程安全
由于Cpython解释器的垃圾回收机制不是线程安全的,保证了数据的安全多线程
优势:保证了数据安全并发
缺点:单个进程下开启多个线程只能实现并发不能实现并行app
单核或多核I/O密集型下使用:多线程性能
单核计算密集型下使用:多线程测试
多核计算密集型下使用:多进程spa
多cpu,意味着能够有多个核并行完成计算,因此多核提高的是计算性能操作系统
每一个cpu一旦遇到I/O阻塞,仍然须要等待,因此多核对I/O操做没什么用处线程
对于一个程序来讲不多是纯IO型或者纯计算型,咱们只能相对的判断是IO密集型仍是计算密集型,来选择多进程仍是多线程
单核状况下:
开启四个任务是计算密集型的,没有多核来并行计算,开多个进程,只是徒增进程的开销内存资源,应该使用多线程
开启四个任务是IO密集型的,开启多进程也是徒增,来回切换的速度还不如开启多线程的,因此应该使用多线程
多核状况下:
开启四个任务是计算密集型的,多核意味着多个CPU去计算,开启多进程能够同一时刻去计算,因此应该使用多进程
开启四个任务是IO密集型的,再多的核也在在等待,来回切换的速度进程不如线程的,因此应该使用多线程
from multiprocessing import Process from threading import Thread import os import time # 计算密集型 def task1(): i = 0 for line in range(110000000): i += 1 if __name__ == '__main__': print(os.cpu_count()) # 查看计算机几核的 list1 = [] start_time = time.time() for i in range(4): p1 = Process(target=task1) # 4进程下: 17.369488954544067 # t1 = Thread(target=task1) # 4线程下: 27.991361618041992 p1.start() # t1.start() # list1.append(t1) list1.append(p1) for i in list1: i.join() end_time = time.time() print(end_time - start_time) # IO密集型 def task2(): time.sleep(1) if __name__ == '__main__': print(os.cpu_count()) start_time = time.time() list2 = [] for i in range(40): # p2 = Process(target=task2) #40进程下: 11.374541282653809 t2 = Thread(target=task2) # 40线程下: 1.010239839553833 # p2.start() t2.start() # list2.append(p2) list2.append(t2) for i in list2: i.join() end_time = time.time() print(end_time - start_time)
进程:资源单位
线程:执行单位
协程:单线程下实现并发
在I/O密集型的状况下,使用协程提升执行效率
手动的实如今同一线程下 “ 遇到I/O切换+保存状态 ” 让操做系统误觉得没有I/O操做,将CPU执行权限继续交给你
即:在单线程下实现多个任务遇到IO就切换能够下降单线程的IO时间,从而最大限度的提高单线程的效率
gevent模块:遇到I/O自动切换并保存状态
使用gevent模块中的monkey,monkey.patch_all()来监视是否遇到IO操做,再使用spawn来建立协程,使用joinall替代join,使协程运行完再结束线程,joinall中放入获得的对象到列表中
from gevent import spawn from gevent import joinall from gevent import monkey import time # 补丁:监听全部的任务是否有IO操做 monkey.patch_all() def task1(name): print(f'{name}开始') time.sleep(1) print(f'{name}结束') def task2(): print('task2开始') time.sleep(3) print('task2结束') def task3(): print('task3开始') time.sleep(5) print('task3结束') if __name__ == '__main__': start_time = time.time() # 建立协程 sp1 = spawn(task1,'task1') sp2 = spawn(task2) sp3 = spawn(task3) # sp1.join() # sp2.join() # sp3.join() joinall([sp1, sp2, sp3]) # 至关于 sp.join(),注意放入列表中 end_time = time.time() print(end_time - start_time) # task1开始 # task2开始 # task3开始 # task1结束 # task2结束 # task3结束 # 5.013161897659302