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) # <coroutine object task at 0x000001E583341258>
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 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
- 终结python协程----从yield到actor模型的实现
把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...
- 从yield 到yield from再到python协程
yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...
- 用yield实现python协程
刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...
- [转载] Python协程从零开始到放弃
Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC 2017-10-09 3,973 Author: lightless@Meili-inc Date: 2017100 ...
- python 协程的学习记录
协程是个子程序,执行过程中,内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行 从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数.可是,在协程中,yield 通常 ...
- python协程--yield和yield from
字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...
- 00.用 yield 实现 Python 协程
来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...
- python协程详解
目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...
随机推荐
- 【leetcode 简单】第一题 两数之和
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target ...
- E - Travel Cards CodeForces - 847K (思维)
题目链接:https://cn.vjudge.net/contest/272855#problem/E 题目大意:给你n,a,b,k,f.n代表有n次旅行计划,然后a代表一次单程旅行的车费,b代表从下 ...
- Tornado/Python 学习笔记(二)
部分ssrpc.py代码分析 -- 服务端: 1 #!/usr/bin/python3 2 3 from xmlrpc.client import Fault, dumps, loads 4 impo ...
- 简单漂亮的php验证码函数
/* *说明:函数功能是生成验证码 * 参数说明:输入 长度,宽度,高度 */ function vcode($_code_length = , $_width = , $_height = ){ $ ...
- ISG2018 web题Writeup
0x01.命令注入 这题可以使用burpsuite扫出来,但是可能需要测一下. 得知payload为:i%7cecho%20gzavvlsv9c%20q9szmriaiy%7c%7ca%20%23'% ...
- 33 - 并发编程-线程同步-Event-lock
目录 1 线程同步 1.1 Event 1.1.1 什么是Flag? 1.1.2 Event原理 1.1.3 吃包子 1.2 Lock 1.2.1 lock方法 1.2.2 计数器 1.2.3 非阻塞 ...
- 【Python学习】request库
Requests库(https://www.python-requests.org/)是一个擅长处理那些复杂的HTTP请求.cookie.header(响应头和请求头)等内容的Python第三方库. ...
- MySQL之——如何添加新数据库到MySQL主从复制列表 【转】
转自 转载请注明出处:http://blog.csdn.net/l1028386804/article/details/54653691 MySQL主从复制一般情况下我们会设置需要同步的数据库,使用参 ...
- http 错误代码解释 && nginx 自定义错误【转】
如果向您的服务器发出了某项请求要求显示您网站上的某个网页(例如,当用户通过浏览器访问您的网页或在 Googlebot 抓取该网页时),那么,您的服务器会返回 HTTP 状态代码以响应该请求. 此状态代 ...
- 设计模式之笔记--职责链模式(Chain of Responsibility)
职责链模式(Chain of Responsibility) 定义 职责链模式(Chain of Responsibility),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系 ...