首先了解一下协程,协程的本质就是一条线程,多个任务在一条线程上来回切换,协程的所有切换都是基于用户,只有在用户级别才能感知到的 IO 才会用协程模块来规避,在 python 中主要使用的协程模块是 asyncio,并且基于 async 和 await 关键字的协程可以实现异步编程,这也是目前 python 异步相关的主流技术。

1.事件循环

事件循环它其实是异步编程中的一个非常重要的环节,可以把它当成一个死循环,它会去检查并执行一些代码。

示例:伪代码

任务列表 = [ 任务1, 任务2, 任务3,... ]

while True:
可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将'可执行'和'已完成'的任务返回 for 就绪任务 in 已准备就绪的任务列表:
执行已就绪的任务 for 已完成的任务 in 已完成的任务列表:
在任务列表中移除 已完成的任务 如果 任务列表 中的任务都已完成,则终止循环

通过上述伪代码就会发现这个事件循环就是可以理解成一个死循环在检查一个列表里的任务,如果列表里面的任务是可执行的,那就去执行这个任务,如果是不可执行(指的是遇到 IO 操作)的,那么在检查的时候就根本检查不到,相当于把 这个任务忽略掉,认为它不需要被执行,让它一直在等待着 IO 请求,当 IO 完成之后在去执行这个任务。

获取和创建事件循环

import asyncio

# 生成和获取一个事件循环
loop = asyncio.get_event_loop() # 给事件循环添加任务,让事件循环去检测这个任务的状态是否可运行
loop.run_until_complete(任务)

2.async

async 是一个关键字,用于定义一个协程函数。

协程函数:定义函数的时候使用 async def 函数名

协程对象:执行 协程函数() 得到的协程对象。

# 定义一个协程函数
async def func():
pass # 调用协程函数,返回一个协程对象
result = func()

调用协程函数的时候,函数内部的代码不会执行,只会返回一个协程对象。

如果想要运行协程函数内部代码,必须要将协程对象交给事件循环来处理。

import asyncio

async def func():
print('这是一个协程函数!') result = func # 方式一:
loop = asyncio.get_event_loop() # 生成一个事件循环
loop.run_until_complete( result ) # 将协程对象添加到事件循环执行 # 方式二:python 3.7 之后使用,本质上还是和上面一样,但是比较简单
asyncio.run( result )

3.await

await 也是一个关键字,它主要是在当前任务1遇到 IO 操作的时候切到其他没有 IO 操作的任务2去执行,让事件循环可以去执行其他任务,当任务1的 IO 操作执行完后再切换回来执行 await 之后的内容。

await 的后面只能加可等待的对象(协程对象、Task对象 ....)

示例:

import asyncio

async def others():
print('others -----> start')
await asyncio.sleep(2)
print('others -----> end')
return '返回值' async def fun():
print('执行协程函数内部代码!') # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response = await others() # 它会等有返回值了才会继续往下执行
print('IO请求结束,结果为:', response) asyncio.run(fun()) # 输出:
执行协程函数内部代码!
others -----> start
others -----> end
IO请求结束,结果为: 返回值

从上面这个示例可以看出来 await 就是等待对应后面的值得到结果之后,在向下继续执行!

由于在这个示例中事件循环列表中只有一个任务,所以在 IO 等待时无法演示切换到其他任务的执行效果,在程序中如果想要创建多个任务对象,需要使用 Task 对象来实现。

4.Task对象

Task 用于并发调度协程,在事件循环中添加多个任务。

本质上是将协程对象封装成 Task 对象,并将该协程加入事件循环,同时追踪协程的状态。

示例1:通过asyncio.create_task(协程对象)添加任务。

import asyncio

async def func(i):
print(i, '--->start')
await asyncio.sleep(1)
print(i, '--->end')
return f'返回值{i}' async def main():
print('main start') # 创建 Task 对象并添加到事件循环中
task1 = asyncio.create_task(func(1))
task2 = asyncio.create_task(func(2)) print('main end') # 此处await会自动切换执行其他任务。例如:task1,task2
ret1 = await task1
ret2 = await task2
print(ret1, ret2) asyncio.run(main()) # 输出:
main start
main end
1 --->start
2 --->start
1 --->end
2 --->end
返回值1 返回值2

示例2:通过asyncio.wait(协程对象列表)添加任务,在它的源码中会通过 ensure_future 把每个协程封装成 Task 对象。

import asyncio

async def func(i):
print(i, '--->start')
await asyncio.sleep(1) # 当遇到IO操作挂起当前协程并切换其他协程
print(i, '--->end')
return f'返回值{i}' task_list = [func(1), func(2)] # 如果设置了 timeout 值,则意味着此处最多等待的秒,完成的协程返回值写入done中,未完成的写入pending
done, pending = asyncio.run(asyncio.wait(task_list, timeout=None)) # 输出:
1 --->start
2 --->start
1 --->end
2 --->end

asyncio 异步编程的更多相关文章

  1. asyncio异步编程【含视频教程】

    不知道你是否发现,身边聊异步的人越来越多了,比如:FastAPI.Tornado.Sanic.Django 3.aiohttp等. 听说异步如何如何牛逼?性能如何吊炸天....但他到底是咋回事呢? 本 ...

  2. asyncio异步编程

    1. 协程 协程不是计算机提供,程序员认为创造 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术,其实就是一个线程实现代码块相互切换执行.例如: def func1(): ...

  3. 在Python中使用asyncio进行异步编程

    对于来自JavaScript编码者来说,异步编程不是什么新东西,但对于Python开发者来说,async函数和future(类似JS的promise)可不是那么容易能理解的. Concurrency ...

  4. Python 异步编程笔记:asyncio

    个人笔记,不保证正确. 虽然说看到很多人不看好 asyncio,但是这个东西还是必须学的.. 基于协程的异步,在很多语言中都有,学会了 Python 的,就一通百通. 一.生成器 generator ...

  5. python3.6以上 asyncio模块的异步编程模型 async await语法

    这是python3.6以上版本的用法,本例是python3.7.2编写使用asyncio模块的异步编程模型,生产这消费者,异步生产,用sleep来代替IO等待使用async和await语法来进行描述a ...

  6. Python网络编程(4)——异步编程select & epoll

    在SocketServer模块的学习中,我们了解了多线程和多进程简单Server的实现,使用多线程.多进程技术的服务端为每一个新的client连接创建一个新的进/线程,当client数量较多时,这种技 ...

  7. 深入理解 Python 异步编程(上)

    http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...

  8. asyncio异步IO--协程(Coroutine)与任务(Task)详解

    摘要:本文翻译自Coroutines and Tasks,主要介绍asyncio中用于处理协程和任务的方法和接口.在翻译过程中,译者在官方文档的基础上增加了部分样例代码和示意图表,以帮助读者对文档的理 ...

  9. asyncio并发编程

    一. 事件循环 1.注: 实现搭配:事件循环+回调(驱动生成器[协程])+epoll(IO多路复用),asyncio是Python用于解决异步编程的一整套解决方案: 基于asynico:tornado ...

随机推荐

  1. jQuery--选择器案例实战

    1.案例需求 jquery最基础的选择器部分已经基本结束,来一个简单案例总结回顾下学的东西. 案例需求: 用一个按钮控制元素的显示与隐藏,页面如下,从第五个开始,不要最后一个,控制他们的显示和隐藏. ...

  2. 部署新项目自动对数据库进行migrate和让用户收到创建用户/超级用户信息

    当项目中的models有数据表的时候,普通做法是用docke exec -it hello_web_1 bash,进入容器进行migrate,但是我们想要容器一启动就自动创建数据表,可以修改docke ...

  3. Django用mongoengine操作mongodb

    最近在写Django项目,使用的是mongodb,虽然Django不支持NoSQL,但是mongoengine可以帮助我们像ORM一样在Django项目中去操作mongodb 推荐一个可视化工具  R ...

  4. 数据结构:DHU顺序表ADT模板设计及简单应用:找匹配

    顺序表ADT模板设计及简单应用:找匹配 时间限制: 1S类别: DS:线性表->线性表应用 问题描述: 输入范例: 100000100000 99999 99998 99997 99996 99 ...

  5. UP9616移动电源快充案例

    第一版的UP9616快充(地址在此 ),从选料到线路板的布局走线都还算不错,实现了当初定下的设计目标,但也有一点小小的遗憾,就是在输出滤波电容这里有点随便了,为了弥补这个遗憾,秉着工程师的" ...

  6. 又快又好!巧用ChartJS打造你的实用折线图

    又快又好!巧用ChartJS打造你的实用折线图 最终效果 本示例利用官方示例改造而成,生成带图示的折线图,标出各折线的名称,可以筛选想要显示的折线. 要实现最终效果,我们要分三步走: 生成折线图: 生 ...

  7. 前端调试利器 - Charles

    Docs 开发之 Charles 配置指南 1.下载与安装 charles-proxy-4.1.4 .dmg56.12 MB已存到云盘下载 2.激活 使用公司正版license 激活 安装证书 点击证 ...

  8. CCF201709-2公共钥匙盒改进版

    问题描述 有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家.每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中 ...

  9. 【001】学习前提——安装linux虚拟机,搭建docker

    1. 配置linux 1.1 修改配置 安装virtualbox的过程略过. 进入cd /etc/sysconfig/network-scripts,编辑:vi ifcfg-enp0s3 1>将 ...

  10. 【合集】Python基础知识【第二版】

    更新部分 为了避免冗长的代码影响大家观感,将部分案例拆开 增加部分知识点,为了减少大家阅读的负担,尽可能使用短句子,但知识点不可能全覆盖,笔者不是写书,就算是写书也不可能全面,请同学们自行去补充 增加 ...