python 内置模块asyncio,协程

一、简介

协程(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会报错
三、方法
  1. asyncio.run(coro,debug=False) 运行协程对象,coro协程对象、debug是否开启调试模式
  2. 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会报错
    
  1. asyncio.ensure_future(coro) 同create_task一样,并发运行多个协程,区别ensure_future适用于 >=3.6,create_task适用于 >=3.7,返回一个asyncio.Future对象
  2. asyncio.isfuture(obj) 判断一个对象是不是future
  3. asyncio.iscoroutine(obj) 判断一个对象是不是coro
  4. 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) 设置事件循环调试模式
  1. 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())
    
  2. asyncio.set_event_loop(loop) 将loop设置为当前事件循环
  3. asyncio.new_event_loop() 创建并返回一个新的事件循环对象,同样具有asyncio.get_event_loop() 下的方法
  4. 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会报错
    
  5. 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会报错
    
  6. 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('超时')
    
  7. 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会报错
    
  8. asyncio.get_event_loop_policy() 获取当前事件循环策略
  9. asyncio.set_event_loop_policy() 设置当前事件循环策略,如:uvloop
  10. asyncio.Semaphore() 信号量锁,等同于线程、进程中的锁
  11. asyncio.BoundedSemaphore() 信号量锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
  12. asyncio.Condition() 条件锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
  13. asyncio.Event() 事件锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
  14. asyncio.Lock() 互斥锁,等同于线程、进程中的锁,区别在于上锁时需加上await:await lock.acquire()
  15. asyncio.run_coroutine_threadsafe() 类似事件循环中的loop.call_soon_threadsafe,区别在于loop.call_soon_threadsafe执行的是普通函数,asyncio.run_coroutine_threadsafe执行的是协程函数
  16. asyncio.wrap_future(concurrent.future.Future) 包装成协程的 Future 对象
四:其他
  1. 使用其他循环策略:uvloop,uvloop可以在一定程度上提高事件循环的效率,需安装依赖:pip install uvloop;不支持windows
    import uvloop
    
    # 将asyncio中的事件循环替换成uvloop中的事件循环
    asyncio.set_event_loop(uvloop.EventLoopPolicy())
    
  2. 上下文管理器,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())
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

局外人LZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值