python并发、异步—协程

单个线程下实现并发,伪并发,适合io密集型的项目

本文只讲3.5之后的async、await关键字

基础

asyncio该库是python3.4之后出的,支持并发、异步、协程

一些关键字说明:

async:声明协程的关键字,在定义函数关键字之前

await:用于挂起阻塞的异步调用接口,后边只能跟__wait__的对象或者是携程

get_running_loop:程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数

coroutine :协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用

task :(任务)一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态

future:代表将来执行或没有执行的任务的结果。它和task上没有本质上的区别

run_in_executor把普通函数转化成asyncio的future对象

  • 定义协程

协程函数

import asyncio, time


async def func(n):
    time.sleep(n)
    print("lynn", n)


run_func = func(5) # 协程对象
loop = asyncio.get_event_loop() # 开启一个循环
loop.run_until_complete(run_func) # 把写成注册到循环里

这样是阻塞的,同步的

协程对象内部代码不执行

被async声明的函数就是一个协程,不能像一般函数那样调用会报:

sys:1: RuntimeWarning: coroutine 'func' was never awaited
  • 调用协程

1 python3.7之前

import asyncio


async def func():
    print("async")
    return "async"


if __name__ == '__main__':
    loop = asyncio.get_event_loop() # 获取事件循环
    # task = loop.create_task(func())
    # 或者
    task = asyncio.ensure_future(func()) # 将任务放到任务列表
    res = loop.run_until_complete(task) 
    print("res:", res)

2 python3.7之后

import asyncio


async def func():
    print("async")
    return "async"


if __name__ == '__main__':
    res = asyncio.run(func())
    print("res:", res)
  • 创建task(任务)

协程不能直接调用,在注册事件循环的时候,其实是run_until_complete方法将协程包装成为了一个任务(task)对象。task对象是Future类的子类,保存了协程运行后的状态,用于未来获取协程的结果

import asyncio, time


async def func(n):
    time.sleep(n)
    print("lynn", n)


run_func = func(5)
loop = asyncio.get_event_loop()
task = loop.create_task(run_func)
print(task) # 该状态是 <Task pending coro=<func() running at /Users/tianzhh/Desktop/es_learn/as.py:4>>
loop.run_until_complete(task)
print(task) # 该状态是 <Task finished coro=<func() done, defined at /Users/tianzhh/Desktop/es_learn/as.py:4> result=None>
print("ok") 

是阻塞的,同步

  • 绑定回调

task运行完成拿不到返回值,通过回调拿到返回值,然后操作

import asyncio, time


async def func(n):
    time.sleep(n)
    print("lynn", n)
    return "lynn-{}".format(n)

def call_back_func(future):
    print("result", future.result()) # 拿到协程的返回值

run_func = func(5)
loop = asyncio.get_event_loop()
task = loop.create_task(run_func)
task.add_done_callback(call_back_func) # 加入回调函数
loop.run_until_complete(task)
print("ok")

详细用法

await

后边跟可等待的对象(协程对象、Future对象、Task对象)

import asyncio


async def other():
    await asyncio.sleep(2)


async def func():
    print("开始")
    response = await other()
    print("结束", response)
    print("开始")
    response1 = await other()
    print("结束", response1)


if __name__ == '__main__':
    asyncio.run(func())

注意:

​ 遇到await,线程会被阻塞,只有运行完毕后,线程才会继续往下运行。

​ 但是不是同步,是切到别的任务中

task对象

用于并发调度多个协程

import asyncio


async def other():
    await asyncio.sleep(2)


async def func():
    other_task = asyncio.create_task(other()) # 创建task,加到事件循环中
    response = await other_task # 等待运行完,才继续往下进行
    print("response:", response)


if __name__ == '__main__':
    asyncio.run(func())

如果是多个task,一般用这种

import asyncio


async def other():
    print("开始")
    await asyncio.sleep(2)
    print("结束")
    return 100


async def func():
    task_list = [
        asyncio.create_task(other(), name="task1"),
        asyncio.create_task(other(), name="task1"),
    ]
    done, pending = await asyncio.wait(task_list, timeout=10)
    print("response:", done, pending)


if __name__ == '__main__':
    asyncio.run(func())

注意:

asyncio.wait()中参数是列表或者元组,切其中的元素可以是:协程对象、task对象、Future对象

asyncio.create_task()该方法,会在创建task对象的同时,会把task对象加入到事件循环中,所以使用该方法,要先创建时间循环

异步编程

重点:一般用这个

import time, asyncio


def f1(n, m):
    print(n, m)
    time.sleep(n)
    print("普通函数{}".format(n, m))
    return n, m


async def main():
    loop = asyncio.get_event_loop()
    f = loop.run_in_executor(None, f1, 2, 3)
    g = loop.run_in_executor(None, f1, 1, 3)
    f_result = await f
    g_result = await g
    print("result:", f_result)
    print("result:", g_result)
    print("完")


asyncio.run(main())

print("主")

注意:

run_in_executor中只能是普通函数,不能是协程函数,会把普通函数转化为asyncio的future对象,然后await后异步调用不等待,但是会等所有的调用运行完,才继续往下运行

posted @ 2020-09-10 11:27  tianzhh_lynn  阅读(313)  评论(0编辑  收藏  举报