Python 进阶 之 协程
协程的概念级描述(与线程对比):转自知乎 链接
线程有两个必须要处理的问题:一是碰着阻塞式I\O会导致整个进程被挂起;
二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。
如果一种实现使得每个线程需要自己通过调用某个方法,主动交出控制权。那么我们就称这种线程是协作式的,即是协程。
在Python中关于协程的实现方式有三种:
- 最初的生成器变形yield/send
- 引入@asyncio.coroutine和yield from
- 在Python3.5版本中引入async/await关键字
以下代码均在Centos 7 Python3.6调试通过!
简单的yield使用描述:
def fun():
index = 0
while True:
yield index
index += 1
if index > 3 :
break
for i in fun():
print (i)
输出:0 1 2 3
在此例中yield做的事是:
1:将函数fun的返回值设定为一个生成器
2:每次运行至yield index 时会将index的值作为生成器的下一个元素返回值for循环并且被赋值给变量i,用print输出出来
简单的yield/send使用描述:
def fun():
index = 0
while True:
value = yield index
print ("value=" + str(value))
print ("index=" + str(index))
index += 1
if index > 3 :
break
funobj = fun()
print (type(funobj))
print ("next=" + str(next(funobj)))
for i in funobj:
print ("i=" + str(i))
try:
funobj.send(i+100)
except StopIteration:
print("it's stop")
输出:
<class 'generator'>
next=0
value=None
index=0
i=1
value=101
index=1
value=None
index=2
i=3
value=103
index=3
it's stop
不是很精通,因此代码有点乱。
解释:
首先声明了fun函数,并将fun赋给了对面funobj,funobj是一个迭代器。next(funobj)初始化并启动迭代器,程序开始运行fun函数至value = yield index(第一次)结束,yield返回了第一个index值0 next=0
for i in funobj:启动迭代器,因此此时send还未传值,因此value和next都是空,value=None index=0 程序运行fun函数至value = yield index(第二次)结束,yield返回了第二个index值1 i=1
注意之后send发送了值101,for再次启动迭代器,从yield启动时捕获到此值101,value=101 index=101。此后类似。
迭代器结束时会捕获到 StopIteration异常,将此捕获并输出出来 it's stop
简单的yield/send使用描述:
yeild from语法就是将生成器函数中包括yield语句的部分逻辑封装到一个子生成器函数中。然后在子生成器函数外面可以做一些其他的业务逻辑。整个生成器函数(包括子生成器函数)对外就是一个生成器函数。
def fun():
index = 0
while True:
value = yield index
print ("value=" + str(value))
print ("index=" + str(index))
index += 1
if index > 3 :
break def fun2():
print ("before ")
yield from fun()
print ("end ") funobj = fun2()
print (type(funobj))
print ("next=" + str(next(funobj)))
for i in funobj:
print ("i=" + str(i))
try:
funobj.send(i+100)
except StopIteration:
print("it's stop")
输出:
<class 'generator'>
before
next=0
value=None
index=0
i=1
value=101
index=1
value=None
index=2
i=3
value=103
index=3
end
it's stop
简单的asyncio.coroutine使用描述:(参考自廖雪峰的官方网站)
@asyncio.coroutine通过装饰器调用,作用是把一个generator标记为coroutine类型:
import asyncio @asyncio.coroutine
def hello():
print("Hello world!")
# 异步调用asyncio.sleep(1):
r = yield from asyncio.sleep(1)
print("Hello again!") # 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
输出:
Hello world!
Hello again!
简单的async和await使用描述:
async和await是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
- 把
@asyncio.coroutine替换为async; - 把
yield from替换为await。
示例代码:
import asyncio async def hello():
print("Hello world!")
r = await asyncio.sleep(1)
print("Hello again!") # 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
需要注意的是async和await只能用在Python 3.5以及后续版本,如果使用3.4版本,则仍需使用asyncio.coroutine和yield from方案。
示例可能出现的报错如下:
[root@jans test]# python3.6 c.py
Hello world!
Hello again!
[root@jans test]# python3.4 c.py
File "c.py", line 3
async def hello():
^
SyntaxError: invalid syntax
Python 进阶 之 协程的更多相关文章
- Python自动化 【第十篇】:Python进阶-多进程/协程/事件驱动与Select\Poll\Epoll异步IO
本节内容: 多进程 协程 事件驱动与Select\Poll\Epoll异步IO 1. 多进程 启动多个进程 进程中启进程 父进程与子进程 进程间通信 不同进程间内存是不共享的,要想实现两个进程间 ...
- Python进阶:聊协程
从一个爬虫说起 Python 2 的时代使用生成器协程,Python 3.7 提供了新的基于 asyncio 和 async / await 的方法.先看一个简单的爬虫代码,爬虫的 scrawl_pa ...
- 第十一章:Python高级编程-协程和异步IO
第十一章:Python高级编程-协程和异步IO Python3高级核心技术97讲 笔记 目录 第十一章:Python高级编程-协程和异步IO 11.1 并发.并行.同步.异步.阻塞.非阻塞 11.2 ...
- Python中Paramiko协程方式详解
什么是协程 协程我们可以看做是一种用户空间的线程. 操作系统对齐存在一无所知,需要用户自己去调度. 比如说进程,线程操作系统都是知道它们存在的.协程的话是用户空间的线程,操作系统是不知道的. 为什么要 ...
- [转载]Python 3.5 协程究竟是个啥
http://blog.rainy.im/2016/03/10/how-the-heck-does-async-await-work-in-python-3-5/ [译] Python 3.5 协程究 ...
- [译] Python 3.5 协程究竟是个啥
转自:http://blog.rainy.im/2016/03/10/how-the-heck-does-async-await-work-in-python-3-5/ [译] Python 3.5 ...
- python中的协程及实现
1.协程的概念: 协程是一种用户态的轻量级线程.协程拥有自己的寄存器上下文和栈. 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈. 因此,协程能保留 ...
- Python基础之协程
阅读目录 一 引子 二 协程介绍 三 Greenlet模块 四 Gevent模块 引子 之前我们学习了线程.进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位. 按道 ...
- python线程、协程、I/O多路复用
目录: 并发多线程 协程 I/O多路复用(未完成,待续) 一.并发多线程 1.线程简述: 一条流水线的执行过程是一个线程,一条流水线必须属于一个车间,一个车间的运行过程就是一个进程(一个进程内至少一个 ...
随机推荐
- asp.net页面中的Console.WriteLine结果如何查看
其实用Console.WriteLine("xxxxx"),在asp.net Web程序,在输出窗口是不会输出结果的,应该用Debug.WriteLine("xxxxx& ...
- Struts2值栈
一.前言 很多事儿啊,就是“成也萧何败也萧何”,细想一些事儿心中有感,当然,感慨和本文毛关系都没有~想起之前有篇Struts2中值栈的博客还未完工,就着心中的波澜,狂咽一把~ 二.正文 博文基于:st ...
- 【Python】Python 模块一考核
1. #!/usr/bin/python 和#!/usr/bin/env python 含义 大部分python文件的头部都会写上 #!/usr/bin/python 或者 #!/usr/bin/e ...
- P4462 [CQOI2018]异或序列
题目描述 已知一个长度为n的整数数列 a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an ,给定查询参数l.r,问在 al,al+1,...,ara_l,a_{l+1 ...
- 皮肤包项目的 Gradle 脚本演化
我在做的一个项目需要有换肤功能,换肤的方案是采用第三方库 ThemeSkinning 的实现(在其基础上修复若干 bug).皮肤的制作是把相关的资源放在一个 app module 中打包成 apk,当 ...
- MySQL 创建一个简单的成绩管理系统
操作过程使用实验楼. 首先是创建一个数据库studentsystem,使用语句是: CREATE DATABASE studentsystem; 查看创建好的数据库的命令还是SHOW DATABAS ...
- 【BZOJ2134】单选错位 概率DP
一句话:有一些看似有关系的期望在把事件全面发生之后就变得相互独立了 #include<cstdio> using namespace std; ]; double ans; int mai ...
- 【bzoj2141】排队 [国家集训队2011]排队(魏铭) 树套树 线段树套替罪羊树
这个题就是动态偏序对,每次操作做两个删除两个插入就好了. #include<cstdio> #include<iostream> #include<cstring> ...
- bzoj1814 Ural 1519 Formula 1(插头dp模板题)
1814: Ural 1519 Formula 1 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 924 Solved: 351[Submit][Sta ...
- mmall项目之问题一(mavenplugin问题)
在进行mybatis逆向工程到时候,报错,提示maven plugin 错误,提示missing..... 解决办法: 因为之前到pom中忘记了加版本信息,添加后错误消失: