协程
# 协程: # 协程不是计算机提供的,是程序员认为创造的;也称之为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。 # 主要意义:通过一个线程利用其IO等待事件去做一些其它事情。 # 实现协程的几种方式 # greenlet 早期的一个模块 # yield python关键字 # asyncio (py3.4) # async、await python关键字(py3.5) # 一、greenlet # 安装 sudo apt-get install greenlet # 例子: from greenlet import greenlet def func1(): print(1) # 第2步输出:1 gr2.switch()# 第3步切换到func2 print(2) # 第6步输出:2 gr2.switch()# 第7步切换到func2 def func2(): print(3) # 第4步输出:3 gr1.switch()# 第5步切换到func1 print(4) # 第8步输出:4 gr1 = greenlet(func1) gr2 = greenlet(func2) gr1.switch() # 第1步开始执行func1函数 # 二、yield关键字 def func1(): yield 1 yield from func2() yield 2 def func2(): yield 3 yield 4 f1 = func1() for item in f1: print(item) # 三、asyncio (py3.4及之后版本才自带) import asyncio @asyncio.coroutine def func1(): print(1) yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数 print(2) @asyncio.coroutine def func2(): print(3) yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数 print(4) tasks = [ asyncio.ensure_future( func1() ), asyncio.ensure_future( func2() ) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) # 四、async & await关键字 import asyncio async def func1(): print(1) await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数 print(2) async def func2(): print(3) await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数 print(4) tasks = [ asyncio.ensure_future( func1() ), asyncio.ensure_future( func2() ) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) # 协程的一些概念 # async 关键字 # 协程函数:定义函数时候用 async def 前缀的函数叫协程函数 async def func(): pass # 协程对象:执行协程函数得到的协程对象。 result = func() # 这里func返回的是协程对象,func函数中的代码并不会执行 # 协程函数不是直接调用的,携程函数需要执行的话需要用协程事件去执行 loop = asyncio.get_event_loop() loop.run_until_complete(result) asyncio.run( result ) # 这是python3.7及以后版本将上面两句简洁化了一下 # await 关键字 # await + 可等待对象(协程对象、Future、Task对象->io等待) import asyncio async def others(): # 定义协程函数 print('start') await asyncio.sleep(2) print('end') return '返回值' async def func(): # 定义协程函数 print('执行协程函数内部代码') respose1 = await others() # 等待协程函数执行完成,然后打印返回值 print('io请求结束,结果为:'+ respose1) respose2 = await others() print('io请求结束,结果为:'+ respose2) asyncio.run( func() ) # Task对象 # Task是继承Future # 创建Task对象的方法: # asyncio.create_task() # loop.create_task() # ensoure_future() # 例1:传统方式使用Task async def func(): print(1) await asyncio.sleep(2) print(2) return '返回值' async def main(): print('main开始') # 创建Task对象,将当前执行的func函数任务添加到事件循环 task1 = asyncio.create_task( func() ) # 创建任务前必须先创建事件循环也就是调用asyncio.run task2 = asyncio.create_task( func() ) # 创建的时候就自动将任务放进事件循环等待调度 print('task创建完成') await asyncio.sleep(5) ret1 = await task1 # 上一行休眠了五秒,在休眠期间task1执行完了的话就直接返回task1任务的执行结果,没有执行完就等待task1任务的执行结果 print('ret1') ret2 = await task2 print('ret2') print(ret1, ret2) asyncio.run( main() ) # 例2:列表方式 import asyncio async def func(): print(1) await asyncio.sleep(2) print(2) return '返回值' async def main(): print('main开始') # task放到列表中 task_list = [ asyncio.create_task( func(), name='t1' ), asyncio.create_task( func(), name='t2' ), ] print('task创建完成') done, pendding = await asyncio.wait(task_list, timeout=None) # done是执行后的返回值,pendding就是timeout超时后挂起(没执行完)的任务信息,一般timeout设置为None print('done:',done) print('pendding:',pendding) asyncio.run( main() ) # 例3:协程对象列表 import asyncio async def func(): print(1) await asyncio.sleep(2) print(2) return '返回值' task_list = [ func(), func(), ] done, pendding = asyncio.run( asyncio.wait( task_list ) ) # 这里的task_list不是Task对象而是协程对象,因为这个时候还没有创建事件循环,所以不能用Task对象 print('done:',done) print('pendding:',pendding) # asyncio.Future对象 # Task继承的Future,Task对象内容await结果的处理基于Future对象来的。 import asyncio async def main(): loop = asyncio.get_running_loop() # 获取当前事件循环对象 fut = loop.create_future() # 创建一个任务(Future对象),这个任务什么都没干 await fut # 等待任务执行结果(future对象),没有结果会一直等下去。 asyncio.run( main() ) # 例2: import asyncio async def set_after(fut): await asyncio.sleep(2) fut.set_result('666') async def main(): loop = asyncio.get_running_loop() # 获取当前事件循环对象 fut = loop.create_future() await loop.create_task(set_after(fut)) data = await fut # Future对象 print(data) asyncio.run( main() ) # 如果函数不支持await怎么处理 import concurrent.futures import time import asyncio import threading def func1(): print('func1 pid', threading.current_thread().ident) time.sleep(3) # 某个耗时操作。如request.get方法不支持asyncio模式,所以只能用线程或进程去实现 return 'sa' async def main(): print('main pid', threading.current_thread().ident) # 写法一 loop = asyncio.get_running_loop() fut = loop.run_in_executor(None, func1) # 将非协程函数,转换为协程Future对象。因为func1不是协程函数,所以没办法用await关键字去异步执行。run_in_executor方法是将func1放到线程池中去执行,然后将提交到线程池中的函数的返回值转换为asyncio.Future对象。所以func1实际上是开的另一个线程去执行的。 result = await fut print('func1 result:', result) # 线程模式 with concurrent.futures.ThreadPoolExecutor() as pool: result = await loop.run_in_executor(pool, func1) print('custom thread pool', result) # 进程模式 with concurrent.futures.ProcessPoolExecutor() as pool: result = await loop.run_in_executor( pool, func1 ) print('costom prosess pool', result) asyncio.run( main() ) # asyncio 异步迭代器 # 实现__aiter__() 和__anext__()方法对象。 import asyncio class Reader(object): def __init__(self): self.count = 0 async def readLine(self): self.count += 1 if self.count == 100: return None return self.count def __aiter__(self): return self async def __anext__(self): val = await self.readLine() # await 必须卸载async函数内 if val == None: raise StopAsyncIteration return val async def func(): obj = Reader() async for item in obj: # 异步迭代器for循环必须卸载协程函数内 print(item) asyncio.run( func() ) # asyncio 异步上下文管理器 import asyncio class AsyncContextManager: def __init__(self, conn): self.conn = conn async def do_something(self): return 666 async def __aenter__(self): return self async def __aexit__(self): await asyncio.sleep(2) async def func(): async with AsyncContextManager(None) as f: # async with必须在协程方法中 result = await f.do_something() print(result) asyncio.run(func()) # uvloop # 是asyncio事件循环的替代方案。uvloop要比python自带的asyncio要快至少两倍。 # 安装: sudo pip3 istall uvloop # 如何将asyncio的事件循环替换成uvloop: import asyncio import uvloop asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) # 这里替换原来的事件循环机制 # ......其它代码不变
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?