几个概念:

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协程(上)相关推荐

  1. python协成_Python协程技术的演进

    引言 1.1. 存储器山 存储器山是 Randal Bryant 在<深入理解计算机系统>一书中提出的概念. 基于成本.效率的考量,计算机存储器被设计成多级金字塔结构,塔顶是速度最快.成本 ...

  2. python asyncio教程_Python 协程模块 asyncio 使用指南

    Python 协程模块 asyncio 使用指南 前面我们通过5 分钟入门 Python 协程了解了什么是协程,协程的优点和缺点和如何在 Python 中实现一个协程.没有看过的同学建议去看看.这篇文 ...

  3. python gevent缺点_python 协程 greenlet gevent

    一.并发的本质 切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长时间片到了 二.协程 ...

  4. 测试python安装成功_Python在Windows上安装配置测试

    Python是跨平台的,它可以运行在Windows.Mac和各种Linux/Unix系统上.在Windows上写Python程序,放到Linux上也是能够运行的. 2.x还是3.x 目前,Python ...

  5. mongodb python 存文件_Python保存MongoDB上的文件到本地的方法介绍

    本文实例讲述了Python保存MongoDB上的文件到本地的方法.分享给大家供大家参考,具体如下: MongoDB上的文档通过GridFS来操作,Python也可以通过pymongo连接MongoDB ...

  6. python显示图片_python 一个figure上显示多个图像的实例

    方法一:主要是inshow()函数的使用 首先基本的画图流程为: import matplotlib.pyplot as plt #创建新的figure fig = plt.figure() #必须通 ...

  7. python开发图片_python实现图片上添加图片

    在介绍完给图上添加文字后,我们再介绍给图片上添加图片,也就是图片的叠加. 需要使用的Python的图像库:PIL.更加详细的知识点如下: Imaga模块:用来创建,打开,保存图片文件 new(path ...

  8. python sendkeys用法_Python Selenium 文件上传之SendKeys

    昨天写了Web 文件下载的ui自动化,下载之后,今天就要写web 文件上传的功能了. 当然从折腾了俩小时才上传成功.下面写一下自己操作的步骤 首先网上说的有很多方法 如 input 标签的最好做了,直 ...

  9. python比例图_python在地图上画比例的实例详解

    现在用python画图已经难不倒一直跟小编学习的小伙伴们了,甚至有的小伙伴画图比小编还要厉害.为此小编还偷偷下了一番功夫,画图这种事情,细节上的完善肯定能让图片更加好看.所以小编知道大家会画地图,但是 ...

最新文章

  1. 树莓派默认密码_用树莓派搭建私人简易网盘 2/5 树莓派4B初始设置
  2. Linux_指令杂烩
  3. 动态创建ActiveRecord条件的查询 MyQuery
  4. 每日一题(53)—— 评价代码片段
  5. E-Learning是学习系统而不是教育系统
  6. 世纪华通与华为签署合作协议,加快推进绿色数据中心建设
  7. php 页面异步刷新,php+jQuery+Ajax简单实现页面异步刷新
  8. 华为ensp模拟器 三层交换机
  9. OA考勤打卡系统功能点
  10. win7计算机备份,使用Win7自带工具对Win7系统进行备份图文详解
  11. FPGA IP核之FIFO
  12. 如何选一款软件助力企业腾飞
  13. 亲自动手写一个深度学习框架
  14. 智能访客机要注意这些陷阱
  15. LCD RGB 控制技术 时钟篇(上)
  16. Windows Server 2012 R2 Standard 安全加固
  17. GMAC接口(3)——传输描述符
  18. 什么是“use strict”,好处和坏处
  19. Kaggle手机验证manually verified
  20. Vj程序设计复杂模拟题训练

热门文章

  1. 第 2-2 课:各种内部类和枚举类 + 面试题
  2. 阿里《Java开发手册》最新嵩山版发布!
  3. 面试官 | Oracle JDK 和 OpenJDK 有什么区别?
  4. 【TensorFlow】 基于视频时序LSTM的行为动作识别
  5. keepalived高可用+nginx负载均衡
  6. 小米用户画像_腾讯企鹅智库发布手机品牌用户画像:华为一二线城市用户少于小米...
  7. c++ hough变换代码_hough变换原理以及实现(转载)
  8. c语言调用createthread线程的头文件_易语言API多线程总汇
  9. 校运会计算机科学系大本营,计算机系团总支学生会学期总结大会
  10. 2345王牌浏览器网页加载慢怎么办 网页加载慢解决