### 9.8 协程 进程、线程、协程三者的区别: - 进程:是资源分配最小的单位 - 线程:是CPU执行的最小单位 - 协程:用户级别的,由我们自己写的python代码来控制切换的,操作系统不可见 协程的意义: ```python #在Cpython解释器下 - 协程和线程都不能利用多核,都是在一个CPU上轮流执行 # 由于多线程本身就不能利用多核 # 所以即便是开启了多个线程也只能轮流在一个CPU上执行 # 协程如果把所有任务的IO操作都规避掉,只剩下需要使用CPU的操作 # 就意味着协程就可以做到题高CPU利用率的效果 ``` 多线程和协程: ```python # 线程 切换需要操作系统,开销大,操作系统不可控,给操作系统的压力大 # 操作系统对IO操作的感知更加灵敏 # 协程 切换需要python代码,开销小,用户操作可控,完全不会增加操作系统的压力 # 用户级别能够对IO操作的感知比较低 注意:我们写的协程只能切换我们能够感知到的IO操作,但是对于无法感知的IO操作依然需要依赖线程 ``` #### 9.8.1 gevent模块 ```python import time import gevent from gevent import monkey #本来gevent模块不认识time模块,这个帮助识别 monkey.patch_all() def eat(): print('liujia is eating') time.sleep(1) print('liujia finished eat') def sleep(): print('liudanni is sleep') time.sleep(1) print('liudanni finised') g1 = gevent.spawn(eat) #创造一个协程任务,遇到IO操作就自动切换 g2 = gevent.spawn(sleep) g1.join() #阻塞,直到g1任务完成为止 如果不阻塞切换了就不会切换回来了 g2.join() gevent.joinall([g1,g2]) #将要阻塞的统一放进来阻塞 print(g1.value) #取结果 #开启10个协程 g_l = [] for i inrange(10): g = gevent.spawn(eat) g_l.append(g) gevent.joinall(g_l) ``` #### 9.8.2 asyncio模块 ```python #启动一个任务 async def demo(): #协程方法 print('start') await asyncio.sleep(1) #阻塞 print('end') loop = asyncio.get_event_loop() #创建一个时间循环 loop.eun_until_complete(demo()) #把demo任务丢到时间循环中去执行 ``` ```python #地洞多个任务,并且没有返回值 async def demo(): # 协程方法 print('start') await asyncio.sleep(1) # 阻塞 print('end') loop = asyncio.get_event_loop() # 创建一个事件循环 wait_obj = asyncio.wait([demo(),demo(),demo()]) loop.run_until_complete(wait_obj) ``` ```python #启动多个任务并且有返回值 async def demo(): # 协程方法 print('start') await asyncio.sleep(1) # 阻塞 print('end') return 123 loop = asyncio.get_event_loop() t1 = loop.create_task(demo()) t2 = loop.create_task(demo()) tasks = [t1,t2] wait_obj = asyncio.wait([t1,t2]) loop.run_until_complete(wait_obj) for t in tasks: print(t.result()) ``` ```python #谁先回来先取谁的结果 import asyncio async def demo(i): # 协程方法 print('start') await asyncio.sleep(10-i) # 阻塞 print('end') return i,123 async def main(): task_l = [] for i in range(10): task = asyncio.ensure_future(demo(i)) task_l.append(task) for ret in asyncio.as_completed(task_l): res = await ret print(res) loop = asyncio.get_event_loop() loop.run_until_complete(main()) ```