python协成_Python协程(上)
几个概念:
event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。
future: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
async/await 关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。
定义协程
通过async关键字定义一个协程(coroutine),协程也是一种对象。协程不能直接运行,需要把协程加入到事件循环(loop),由后者在适当的时候调用协程。asyncio.get_event_loop方法可以创建一个事件循环,然后使用run_until_complete将协程注册到事件循环,并启动事件循环。
import time
import asyncio
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine)
print('用时:', time.time()-start)
创建task
协程对象不能直接运行,在注册事件循环的时候,其实是run_until_complete方法将协程包装成为了一个任务(task)对象。所谓task对象是Future类的子类。保存了协程运行后的状态,用于未来获取协程的结果。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine) # task = asyncio.ensure_future(coroutine)
print(task)
loop.run_until_complete(task)
print(task)
print('用时:', time.time() - start)
创建task后,task在加入事件循环之前是pending状态,执行之后是finished状态。
asyncio.ensure_future(coroutine) 和loop.create_task(coroutine)
都可以创建一个task,run_until_complete的参数是一个futrue对象。当传入一个协程,其内部会自动封装成task,task是Future的子类。isinstance(task, asyncio.Future)将会输出True。
绑定回调
绑定回调,在task执行完毕的时候可以获取执行的结果,回调的最后一个参数是future对象,通过该对象可以获取协程返回值。如果回调需要多个参数,可以通过偏函数导入。
import time
import asyncio
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
def callback(future):
print('Callback: ', future.result())
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
loop.run_until_complete(task)
coroutine执行结束时候会调用回调函数。并通过参数future获取协程执行的结果。我们创建的task和回调里的future对象,实际上是同一个对象。
future 与 result
回调中我们使用了future对象的result方法。前面不绑定回调的例子中,我们可以看到task有fiinished状态。在那个时候,可以直接读取task的result方法。
async def task(x):
print('Waiting {}'.format(x))
return 'Done after {}s'.format(x)
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
# task.result()是协程对象的返回值
print('Task result: {}'.format(task.result()))
阻塞和await
使用async可以定义协程对象,使用await可以针对耗时的操作进行挂起,就像生成器里的yield一样,函数让出控制权。协程遇到await,事件循环将会挂起该协程,执行别的协程,直到其他的协程也挂起或者执行完毕,再进行下一个协程的执行。
耗时的操作一般是一些IO操作,例如网络请求,文件读取等。我们使用asyncio.sleep函数来模拟IO操作。协程的目的也是让这些IO操作异步化。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task result: ', task.result())
print('Time: ', time.time() - start)
在 sleep的时候,使用await让出控制权。即当遇到阻塞调用的函数的时候,使用await方法将协程的控制权让出,以便loop调用其他的协程。现在我们的例子就用耗时的阻塞操作了。
并发和并行
asyncio实现并发,就需要多个协程来完成任务,每当有任务阻塞的时候就await,然后其他协程继续工作。创建多个协程的列表,然后将这些协程注册到事件循环中。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
coroutine1 = task(1) #
coroutine2 = task(2)
coroutine3 = task(4)
loop = asyncio.get_event_loop()
tasks = [ # 创建任务
asyncio.ensure_future(coroutine1),
asyncio.ensure_future(coroutine2),
asyncio.ensure_future(coroutine3)
]
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print('Task result: ', task.result())
print('Time: ', time.time() - start)
# 当任务比较多的时候,可以使用列表生成式,效果是一样的。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(task(i)) for i in [1,2,4]]
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print('Task result: ', task.result())
print('Time: ', time.time() - start)
使用aysncio实现了并发。asyncio.wait(tasks) 也可以使用 asyncio.gather(*tasks) ,前者接受一个task列表,后者接收一堆task。
python协成_Python协程(上)相关推荐
- python协成_Python协程技术的演进
引言 1.1. 存储器山 存储器山是 Randal Bryant 在<深入理解计算机系统>一书中提出的概念. 基于成本.效率的考量,计算机存储器被设计成多级金字塔结构,塔顶是速度最快.成本 ...
- python asyncio教程_Python 协程模块 asyncio 使用指南
Python 协程模块 asyncio 使用指南 前面我们通过5 分钟入门 Python 协程了解了什么是协程,协程的优点和缺点和如何在 Python 中实现一个协程.没有看过的同学建议去看看.这篇文 ...
- python gevent缺点_python 协程 greenlet gevent
一.并发的本质 切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长时间片到了 二.协程 ...
- 测试python安装成功_Python在Windows上安装配置测试
Python是跨平台的,它可以运行在Windows.Mac和各种Linux/Unix系统上.在Windows上写Python程序,放到Linux上也是能够运行的. 2.x还是3.x 目前,Python ...
- mongodb python 存文件_Python保存MongoDB上的文件到本地的方法介绍
本文实例讲述了Python保存MongoDB上的文件到本地的方法.分享给大家供大家参考,具体如下: MongoDB上的文档通过GridFS来操作,Python也可以通过pymongo连接MongoDB ...
- python显示图片_python 一个figure上显示多个图像的实例
方法一:主要是inshow()函数的使用 首先基本的画图流程为: import matplotlib.pyplot as plt #创建新的figure fig = plt.figure() #必须通 ...
- python开发图片_python实现图片上添加图片
在介绍完给图上添加文字后,我们再介绍给图片上添加图片,也就是图片的叠加. 需要使用的Python的图像库:PIL.更加详细的知识点如下: Imaga模块:用来创建,打开,保存图片文件 new(path ...
- python sendkeys用法_Python Selenium 文件上传之SendKeys
昨天写了Web 文件下载的ui自动化,下载之后,今天就要写web 文件上传的功能了. 当然从折腾了俩小时才上传成功.下面写一下自己操作的步骤 首先网上说的有很多方法 如 input 标签的最好做了,直 ...
- python比例图_python在地图上画比例的实例详解
现在用python画图已经难不倒一直跟小编学习的小伙伴们了,甚至有的小伙伴画图比小编还要厉害.为此小编还偷偷下了一番功夫,画图这种事情,细节上的完善肯定能让图片更加好看.所以小编知道大家会画地图,但是 ...
最新文章
- 树莓派默认密码_用树莓派搭建私人简易网盘 2/5 树莓派4B初始设置
- Linux_指令杂烩
- 动态创建ActiveRecord条件的查询 MyQuery
- 每日一题(53)—— 评价代码片段
- E-Learning是学习系统而不是教育系统
- 世纪华通与华为签署合作协议,加快推进绿色数据中心建设
- php 页面异步刷新,php+jQuery+Ajax简单实现页面异步刷新
- 华为ensp模拟器 三层交换机
- OA考勤打卡系统功能点
- win7计算机备份,使用Win7自带工具对Win7系统进行备份图文详解
- FPGA IP核之FIFO
- 如何选一款软件助力企业腾飞
- 亲自动手写一个深度学习框架
- 智能访客机要注意这些陷阱
- LCD RGB 控制技术 时钟篇(上)
- Windows Server 2012 R2 Standard 安全加固
- GMAC接口(3)——传输描述符
- 什么是“use strict”,好处和坏处
- Kaggle手机验证manually verified
- Vj程序设计复杂模拟题训练
热门文章
- 第 2-2 课:各种内部类和枚举类 + 面试题
- 阿里《Java开发手册》最新嵩山版发布!
- 面试官 | Oracle JDK 和 OpenJDK 有什么区别?
- 【TensorFlow】 基于视频时序LSTM的行为动作识别
- keepalived高可用+nginx负载均衡
- 小米用户画像_腾讯企鹅智库发布手机品牌用户画像:华为一二线城市用户少于小米...
- c++ hough变换代码_hough变换原理以及实现(转载)
- c语言调用createthread线程的头文件_易语言API多线程总汇
- 校运会计算机科学系大本营,计算机系团总支学生会学期总结大会
- 2345王牌浏览器网页加载慢怎么办 网页加载慢解决