Python 协程总结
Python 协程总结
理解
协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是之前的。
优点:
- 极高的执行效率,因为子程序切换而不是线程切换,没有了线程切换的开销;
- 不需要多线程的锁机制,因为只有一个线程在执行;
如果要充分利用CPU多核,可以通过使用多进程+协程的方式
使用
打开asyncio的源代码,可以发现asyncio中的需要用到的文件如下:

下面的则是接下来要总结的文件
| 文件 | 解释 |
|---|---|
| base_events | 基础的事件,提供了BaseEventLoop事件 |
| coroutines | 提供了封装成协程的类 |
| events | 提供了事件的抽象类,比如BaseEventLoop继承了AbstractEventLoop |
| futures | 提供了Future类 |
| tasks | 提供了Task类和相关的方法 |
coroutines
| 函数 | 解释 |
|---|---|
| coroutine(func) | 为函数加上装饰器 |
| iscoroutinefunction(func) | 判断函数是否使用了装饰器 |
| iscoroutine(obj) | 判断该对象是否是装饰器 |
如果在函数使用了coroutine装饰器,就可以通过yield from去调用async def声明的函数,如果已经使用async def声明,就没有必要再使用装饰器了,这两个功能是一样的。
import asyncio
@asyncio.coroutine
def hello_world():
print("Hello World!")
async def hello_world2():
print("Hello World2!")
print('------hello_world------')
print(asyncio.iscoroutinefunction(hello_world))
print('------hello_world2------')
print(asyncio.iscoroutinefunction(hello_world2))
print('------event loop------')
loop = asyncio.get_event_loop()
# 一直阻塞该函数调用到函数返回
loop.run_until_complete(hello_world())
loop.run_until_complete(hello_world2())
loop.close()
上面的代码分别使用到了coroutine装饰器和async def,其运行结果如下:
------hello_world------True------hello_world2------True------event loop------Hello World!Hello World2!
注意:不可以直接调用协程,需要一个event loop去调用。
如果想要在一个函数中去得到另外一个函数的结果,可以使用yield from或者await,例子如下:
import asyncio
async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y
async def print_sum(x, y):
result = await compute(x, y)
print("%s + %s = %s" % (x, y, result))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
函数print_sum会一直等到函数compute返回结果,执行过程如下:

base_events
这个文件里面漏出来的只有BaseEventLoop一个类,它的相关方法如下:
| 函数 | 解释 |
|---|---|
| create_future() | 创建一个future对象并且绑定到事件上 |
| create_task() | 创建一个任务 |
| run_forever() | 除非调用stop,否则事件会一直运行下去 |
| run_until_complete(future) | 直到future对象执行完毕,事件才停止 |
| stop() | 停止事件 |
| close() | 关闭事件 |
| is_closed() | 判断事件是否关闭 |
| time() | 返回事件运行时的时间 |
| call_later(delay, callback, *args) | 设置一个回调函数,并且可以设置延迟的时间 |
| call_at(when, callback, *args) | 同上,但是设置的是绝对时间 |
| call_soon(callback, *args) | 马上调用 |
events
| 函数 | 解释 |
|---|---|
| get_event_loop() | 返回一个异步的事件 |
| ... | ... |
返回的就是BaseEventLoop的对象。
future
Future类的相关方法如下:
| 方法 | 解释 |
|---|---|
| cancel() | 取消掉future对象 |
| cancelled() | 返回是否已经取消掉 |
| done() | 如果future已经完成则返回true |
| result() | 返回future执行的结果 |
| exception() | 返回在future中设置了的exception |
| add_done_callback(fn) | 当future执行时执行回调函数 |
| remove_done_callback(fn) | 删除future的所有回调函数 |
| set_result(result) | 设置future的结果 |
| set_exception(exception) | 设置future的异常 |
设置future的例子如下:
import asyncio
async def slow_operation(future):
await asyncio.sleep(1) # 睡眠
future.set_result('Future is done!') # future设置结果
loop = asyncio.get_event_loop()
future = asyncio.Future() # 创建future对象
asyncio.ensure_future(slow_operation(future)) # 创建任务
loop.run_until_complete(future) # 阻塞直到future执行完才停止事件
print(future.result())
loop.close()
run_until_complete方法在内部通过调用了future的add_done_callback,当执行future完毕的时候,就会通知事件。
下面这个例子则是通过使用future的add_done_callback方法实现和上面例子一样的效果:
import asyncio
async def slow_operation(future):
await asyncio.sleep(1)
future.set_result('Future is done!')
def got_result(future):
print(future.result())
loop.stop() # 关闭事件
loop = asyncio.get_event_loop()
future = asyncio.Future()
asyncio.ensure_future(slow_operation(future))
future.add_done_callback(got_result) # future执行完毕就执行该回调
try:
loop.run_forever()
finally:
loop.close()
一旦slow_operation函数执行完毕的时候,就会去执行got_result函数,里面则调用了关闭事件,所以不用担心事件会一直执行。
task
Task类是Future的一个子类,也就是Future中的方法,task都可以使用,类方法如下:
| 方法 | 解释 |
|---|---|
| current_task(loop=None) | 返回指定事件中的任务,如果没有指定,则默认当前事件 |
| all_tasks(loop=None) | 返回指定事件中的所有任务 |
| cancel() | 取消任务 |
并行执行三个任务的例子:
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number+1):
print("Task %s: Compute factorial(%s)..." % (name, i))
await asyncio.sleep(1)
f *= i
print("Task %s: factorial(%s) = %s" % (name, number, f))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
))
loop.close()
执行结果为
Task A: Compute factorial(2)...Task B: Compute factorial(2)...Task C: Compute factorial(2)...Task A: factorial(2) = 2Task B: Compute factorial(3)...Task C: Compute factorial(3)...Task B: factorial(3) = 6Task C: Compute factorial(4)...Task C: factorial(4) = 24
可以发现,ABC同时执行,直到future执行完毕才退出。
下面一些方法是和task相关的方法
| 方法 | 解释 |
|---|---|
| as_completed(fs, *, loop=None, timeout=None) | 返回是协程的迭代器 |
| ensure_future(coro_or_future, *, loop=None) | 调度执行一个 coroutine object:并且它封装成future。返回任务对象 |
| async(coro_or_future, *, loop=None) | 丢弃的方法,推荐使用ensure_future |
| wrap_future(future, *, loop=None) | Wrap a concurrent.futures.Future object in a Future object. |
| gather(*coros_or_futures, loop=None, return_exceptions=False) | 从给定的协程或者future对象数组中返回future汇总的结果 |
| sleep(delay, result=None, *, loop=None) | 创建一个在给定时间(以秒为单位)后完成的协程 |
| shield(arg, *, loop=None) | 等待future,屏蔽future被取消 |
| wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED) | 等待由序列futures给出的Futures和协程对象完成。协程将被包裹在任务中。返回含两个集合的Future:(done,pending) |
| wait_for(fut, timeout, *, loop=None) | 等待单个Future或coroutine object完成超时。如果超时为None,则阻止直到future完成 |
参考文章
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 ...
- 关于python协程中aiorwlock 使用问题
最近工作中多个项目都开始用asyncio aiohttp aiomysql aioredis ,其实也是更好的用python的协程,但是使用的过程中也是遇到了很多问题,最近遇到的就是 关于aiorwl ...
- 用yield实现python协程
刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...
- [转载] Python协程从零开始到放弃
Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC 2017-10-09 3,973 Author: lightless@Meili-inc Date: 2017100 ...
- 00.用 yield 实现 Python 协程
来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...
- python协程详解
目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...
- Python协程与Go协程的区别二
写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...
随机推荐
- Linux 重启和关机命令
shutdown -r 05:30 在凌晨五点30分关机 shutdown -r 05:30 & 后台执行 shutdown -c 取消前一个关机命令 ...
- Oracle 11g RAC 自动应用PSU补丁简明版
环境:Oracle RAC(GI 11.2.0.4 + DB 11.2.0.4) 本文应用补丁信息: Patch 23615403 - Combo of OJVM Component 11.2.0.4 ...
- org.apache.commons.beanutils.BeanMap简单使用例子
一.org.apache.commons.beanutils.BeanMap; 将一个java bean允许通过map的api进行调用, 几个支持的操作接口: Object get(Object ke ...
- 将HTML导出生成word文档
前言: 项目开发中遇到了需要将HTML页面的内容导出为一个word文档,所以有了这边随笔. 当然,项目开发又时间有点紧迫,第一时间想到的是用插件,所以百度了下.下面就介绍两个导出word文档的方法. ...
- JS弹出下载对话框以及实现常见文件类型的下载
写在前面 JS要实现下载功能,一般都是这么几个过程:生成下载的URL,动态创建一个A标签,并将其href指向生成的URL,然后触发A标签的单击事件,这样就会弹出下载对话框,从而实现了一个下载的功能. ...
- 同一个tomcat多个项目共享session,一个tomcat两个项目共享sessionId
同一个tomcat多个项目共享session,一个tomcat两个项目共享sessionId >>>>>>>>>>>>>& ...
- 拥抱.NET Core系列:Logging (1)
在之前我们简单介绍了 .NET Core 中的 DI组件,没来及了解的童鞋可以翻翻我之前的文章. 接下来会对 .NET Core 中的 Logging 进行介绍. 本文中使用了"Micros ...
- FTP DOS 命令行
1. 在cmd--> 输入ftp 2. 进入ftp输入提示命令行,此时输入open ftp服务器地址,比如我的是本机就: open 127.0.0.1 3. 根据提示输入用户名和密码, 提示登录 ...
- [asp.net mvc 奇淫巧技] 05 - 扩展ScriptBundle,支持混淆加密javascript
一.需求: 在web开发中,经常会处理javascript的一些问题,其中就包括js的压缩,合并,发布版本以及混淆加密等等问题.在asp.net 开发中我们使用ScriptBundle已经可以解决ja ...
- Java项目集成SAP BO
SAP BO报表查看需要登录SAP BO系统,为了方便公司希望将BO报表集成到OA系统中,所以参考网上资料加上与SAP BO的顾问咨询整理出一套通过Java来集成SAP BO的功能. SAPBO中的报 ...