一、简介
协程(Coroutines)是一种比线程更加轻量级的存在,协程函数可以在某个地方挂起去执行别的函数,并且可以返回挂起处继续执行
二、使用
import asyncio
'''
async 声明协程函数,协程函数调用是协程对象
await 后面跟的是一个可等待的对象(coroutine对象、future对象、task对象),await的作用就是等待后面的函数返回结果,只有后面的函数返回结果了,程序才会继续往下执行
asyncio.run() 运行的是协程对象
'''
async def task():
await asyncio.sleep(1)
print('我是async任务...')
for _ in range(5):
asyncio.run(task()) #直接调用task会报错
三、方法
- asyncio.run(coro,debug=False) 运行协程对象,coro协程对象、debug是否开启调试模式
- asyncio.create_task(coro,name) 并发运行多个协程,返回task对象,是future的子类。coro协程对象、name任务名称
- task.get_name() 获取任务名称
- task.set_name(name) 设置名称
'' 这样调用实现不了并发:await asyncio.create_task(task('task3')) 示例中:task1和task2的异步任务是同时出现,定时任务也是同时出现,是并发执行,而task3和task4不是 ''' import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') task1 = asyncio.create_task(task('task1')) task2 = asyncio.create_task(task('task2')) task1_name = await task1 print(f'{task1_name}结束') task2_name = await task2 print(f'{task2_name}结束') '''这样使用实现不了并发''' task3 = await asyncio.create_task(task('task3')) task4 = await asyncio.create_task(task('task4')) print(f'{task3}结束') print(f'{task4}结束') asyncio.run(asyncFun()) #直接调用task会报错
- asyncio.ensure_future(coro) 同create_task一样,并发运行多个协程,区别ensure_future适用于 >=3.6,create_task适用于 >=3.7,返回一个asyncio.Future对象
- asyncio.isfuture(obj) 判断一个对象是不是future
- asyncio.iscoroutine(obj) 判断一个对象是不是coro
- asyncio.get_event_loop() 在主线程中,如果没有被设置过任何事件循环,那么会创建一个事件循环,并返回
- loop.run_until_complete(future) 运行事件循环,直到future运行结束
- loop.run_forever() 一直运行事件循环,知道遇到stop
- loop.create_future(coroutine) 返回一个asyncio.Future对象
''' future.set_result(result):设置future返回值 future.result():获取future返回值 future.done():future是否执行完毕 future.cancelled():future是否取消 future.add_done_callback(futureCallback):执行完毕的回调函数 future.remove_done_callback(futureCallback):移除执行完毕的回调函数 future.cancel():取消future future.get_loop():返回future所绑定的事件循环 future.set_exception(exception):设置future异常 future.exception():获取异常 ''' import asyncio def futureCallback(future): print(future.result()) loop = asyncio.get_event_loop() future = loop.create_future() future.set_result('future') future.add_done_callback(futureCallback) loop.run_until_complete(future) #相当于asyncio.run,>=3.7 运行此代码会警告
- loop.create_task(coro,name) 返回task对象,同asyncio.task,是future的子类
''' loop.create_future+loop.create_task 实现多任务并发 ''' import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def allTask(loop): task1 = loop.create_task(task('task1')) task2 = loop.create_task(task('task2')) await task1 await task2 return task1,task2 def futureCallback(future): for task in future.result(): print(task.result()) loop = asyncio.get_event_loop() future = loop.create_future() future.set_result(loop.run_until_complete(allTask(loop))) future.add_done_callback(futureCallback) loop.run_until_complete(future)
- loop.is_running() 如果事件循环依然在运行,则返回True
- loop.is_closed() 如果事件循环已经close,则返回True
- loop.stop() 停止事件循环
- loop.close() 关闭事件循环
- loop.time() loop内部时间点
- loop.call_later(delay, callback,*args) 事件循环在delay多长时间之后才执行callback函数
import asyncio loop = asyncio.get_event_loop() loop_now_time = lambda :loop.time() start_noe_time =loop_now_time() loop.call_later(1, lambda name:print(f'{name}事件点:{loop_now_time() - start_noe_time}',loop.stop()),'call_later') loop.run_forever()
- loop.call_at(when, callback, *args) 在某一个时刻进行调用回调函数
import asyncio loop = asyncio.get_event_loop() loop_now_time = lambda :loop.time() start_noe_time = loop_now_time() loop.call_at(start_noe_time+1, lambda name:print(f'{name}事件点:{loop_now_time() - start_noe_time}',loop.stop()),'call_at') loop.run_forever()
- loop.call_soon(callback, *args) 在下一个时间循环中立刻调用回调函数
import asyncio import time loop = asyncio.get_event_loop() loop_now_time = lambda :loop.time() loop.call_soon(lambda name:print(f'{name}结束',loop.stop()),'call_soon') loop.run_forever()
- loop.call_soon_threadsafe(callback, *argse) 与 call_soon()类似,等待此函数返回后马上调用回调函数,区别是此线程函数是安全的
- loop.run_in_executor(executor, func, *args) 使不支持协程的任务,支持协程,executor 参数应该是一个concurrent.futures.Executor 实例。如果 executor 是 None ,则使用默认执行程序
''' 实现异步的内部原理 第一步:内部会先调用TreadPoolExector的submit方法去线程中申请一个func_1函数,并返回一个concurrent.futures.Future对象 (与asyncio没有任何关系) 第二步:调用asyncio.wrap_future将concurrent.futures.Future对象包装成asyncio.Future对象 因为concurrent.futures.Future对象不支持await语法,因此需要转换成asyncio.Future对象才能进行使用 ''' import asyncio import time import concurrent.futures def task(name): print(f'{name}:我是async任务...') time.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') loop = asyncio.get_running_loop() task1 = await loop.run_in_executor(None,task,'task1') print(f'{task1}结束') with concurrent.futures.ThreadPoolExecutor() as pool: task2 = await loop.run_in_executor(pool, task, 'task2:线程池') print(f'{task2}结束') with concurrent.futures.ProcessPoolExecutor() as pool: task3 = await loop.run_in_executor(pool, task, 'task3:进程池') print(f'{task3}结束') '''线程+异步内部实现''' with concurrent.futures.ThreadPoolExecutor() as pool: thread_pool_future = pool.submit(task, 'task4:线程池') print(thread_pool_future) task4 = await asyncio.wrap_future(thread_pool_future) print(f'{task4}结束') if __name__ == '__main__': asyncio.run(asyncFun())
- loop.get_debug() 获取事件循环调试模式
- loop.set_debug( bool) 设置事件循环调试模式
- asyncio.get_running_loop() 获取当前正在运行的loop,如果当前主线程中没有正在运行的loop,如果没有就会报RuntimeError 错误,>=3.7,同样具有asyncio.get_event_loop() 下的方法
import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') loop = asyncio.get_running_loop() task1 = loop.create_task(task('task1')) task2 = loop.create_task(task('task2')) task1_name = await task1 print(f'{task1_name}结束') task2_name = await task2 print(f'{task2_name}结束') asyncio.run(asyncFun())
- asyncio.set_event_loop(loop) 将loop设置为当前事件循环
- asyncio.new_event_loop() 创建并返回一个新的事件循环对象,同样具有asyncio.get_event_loop() 下的方法
- asyncio.gather(*coros | *futures | *tasks,return_exceptions=False)) 并发执行多个协程,并返回结果,return_exceptions 是否返回异常数据,为True时,将把异常当作成功处理,False时会等待处理异常
import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') tasks = [task('task1'),task('task2')] task_results = await asyncio.gather(*tasks) print(task_results) asyncio.run(asyncFun()) #直接调用task会报错
- asyncio.wait(*tasks,timeout) 并发执行多个协程,并返回结果和状态,timeout 设置等待时间
import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') tasks = [ asyncio.create_task(task('task1')), asyncio.create_task(task('task2')) ] task_response,task_pendings = await asyncio.wait(tasks) task_result = list(map(lambda task: task.result(),task_response)) print(task_result) asyncio.run(asyncFun()) #直接调用task会报错
- asyncio.wait_for(coro,timeout) 等待协程调用,超时抛出asyncio.TimeoutError错误
import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') try: task_response = await asyncio.wait_for(task('task1'), timeout=2) print(task_response) except asyncio.TimeoutError: print('超时')
- asyncio.as_completed(tasks,timeout) 获取tasks结果,返回tasks生成器,超时抛出asyncio.TimeoutError错误
import asyncio async def task(name): print(f'{name}:我是async任务...') await asyncio.sleep(1) print(f'{name}:我是定时任务...') return name async def asyncFun(): print('我是async任务...') try: tasks = [ asyncio.create_task(task('task1')), asyncio.create_task(task('task2')) ] task_gen = asyncio.as_completed(tasks,timeout=2) for task_item in task_gen: result = await task_item print(result) except asyncio.TimeoutError: print('超时') asyncio.run(asyncFun()) #直接调用task会报错
- asyncio.get_event_loop_policy() 获取当前事件循环策略
- asyncio.set_event_loop_policy() 设置当前事件循环策略,如:uvloop
- asyncio.Semaphore() 信号量锁,等同于线程、进程中的锁
- asyncio.BoundedSemaphore() 信号量锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
- asyncio.Condition() 条件锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
- asyncio.Event() 事件锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
- asyncio.Lock() 互斥锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
- asyncio.run_coroutine_threadsafe() 类似事件循环中的loop.call_soon_threadsafe,区别在于loop.call_soon_threadsafe执行的是普通函数,asyncio.run_coroutine_threadsafe执行的是协程函数
- asyncio.wrap_future(concurrent.future.Future) 包装成协程的 Future 对象
四:其他
- 使用其他循环策略:uvloop,uvloop可以在一定程度上提高事件循环的效率,需安装依赖:pip install uvloop;不支持windows
import uvloop # 将asyncio中的事件循环替换成uvloop中的事件循环 asyncio.set_event_loop(uvloop.EventLoopPolicy())
- 上下文管理器,async with
import asyncio class AsyncContextManager: def __init__(self, conn=None): self.conn = conn async def do_something(self): # 异步读取数据库操作 return '模拟增删改查数据库并返回操作结果...' async def __aenter__(self): self.conn = await asyncio.sleep(1) return self async def __aexit__(self, exec_type, exc_val, exc_tb): ''' with语句运行结束之后触发此方法的运行 exc_type:如果抛出异常, 这里获取异常类型 exc_val:如果抛出异常, 这里显示异常内容 exc_tb:如果抛出异常, 这里显示所在位置, traceback ''' # 异步关闭数据库连接 await asyncio.sleep(1) async def func(): async with AsyncContextManager() as fp: result = await fp.do_something() print(result) asyncio.run(func())