协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。

通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定

通过yield实现基础协程

yield的特点就是能够执行方法函数时,暂停执行,然后再继续往下执行,这样就能够实现方法的切换执行

import time

def dancing():
for i in range(5):
print('正在跳舞。。。。%d' % i)
yield
time.sleep(0.1) def singing():
for i in range(5):
print('正在唱歌。。。。%d' % i)
yield
time.sleep(0.1) def main():
dance = dancing()
sing = singing()
for i in range(5):
next(dance)
next(sing)
time.sleep(0.1) if __name__ == '__main__':
main()

运行结果为:

通过greenlet实现协程

python中的greenlet模块对yield进行封装,从而使得切换任务变的更加简单,使用前先安装:pip install greenlet

greenlet中先创建对象,然后调用switch()方法开始执行程序

import time
from greenlet import greenlet def dancing():
for i in range(10):
print('正在跳舞。。。。。%d' % i)
sing.switch()
time.sleep(0.1) def singing():
for i in range(10):
print('正在唱歌。。。。。%d' % i)
dance.switch()
time.sleep(0.1) # 创建全局greenlet对象
dance = greenlet(dancing)
sing = greenlet(singing) def main():
# 调用执行dance
print('开始执行dance')
dance.switch() if __name__ == '__main__':
main()

运行结果为:

通过gevent实现协程

greenlet已经实现了协程,但是需要手动通过调用switch进行切换,而gevent模块比greenlet更强大的并且能够自动切换任务。

其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

使用前先安装:pip install gevent

gevent的基础使用案例

1.普通的耗时操作写法需要转化为gevent模块中的耗时操作,如time.sleep转化为gevent.sleep

2.使用join()开始执行对象中对应的方法并等待方法执行完成

import gevent
import time def dancing(n):
for i in range(n):
print('正在跳舞...%d' % i)
# time.sleep(0.2)
# 普通的耗时操作,如time.sleep、socket.recv()、socket.connect()等
# 这些代码需要手动转换为gevent模块中对应的方法,才能被gevent认为是耗时操作
# 当gevent遇到了认可的耗时操作后,就会自动切换通过gevent创建的对象
# 若没有遇到耗时操作,则按顺序执行gevent对象
gevent.sleep(0.5) def singing(n):
for i in range(n):
print('正在唱歌...%d' % i)
# time.sleep(0.2)
gevent.sleep(0.5) def main():
print('--------main开始-------')
# 创建对象,这时并没有执行方法里面的代码
dance = gevent.spawn(dancing, 5)
sing = gevent.spawn(singing, 6)
# join()开始执行对象中对应的方法并等待方法执行完成
# 在执行方法的过程中,遇到耗时操作,则自动会切换执行gevent对象中的其他方法。
dance.join()
sing.join()
print('-------main结束--------') if __name__ == '__main__':
main()

运行结果为:

gevent的常用简洁写法

1.导入gevent中的monkey,可以将程序中的普通耗时操作转换为gevent中认可的耗时操作

2.使用gevent.joinall让程序更加简洁

import gevent
from gevent import monkey
import time # 有耗时操作时,需要执行这句话
# 能将普通的耗时操作转换为gevent中的耗时操作,这样就不用手动把耗时操作全都替换成gevent中对应的耗时操作了
monkey.patch_all() def work(name, num):
for i in range(num):
print('%s正在执行。。。。%d' % (name, i))
time.sleep(0.2) def main():
dance = gevent.spawn(work, '小明', 5)
sing = gevent.spawn(work, '小花', 6)
gevent.joinall([dance, sing]) if __name__ == '__main__':
main()

运行结果为:

python-多任务编程05-协程(coroutine)的更多相关文章

  1. 32 python 并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  2. 四 python并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  3. 第十篇.5、python并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  4. 第 12 章 python并发编程之协程

    一.引子 主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只用一个)情况下实现并发,并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作 ...

  5. 37、python并发编程之协程

    目录: 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本节的主题是基于单线程来 ...

  6. python网络编程之协程

    本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的 ...

  7. python并发编程之协程(实践篇)

    一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 对于单线程下,我们不可避免程序中出现io操作,但如果我们 ...

  8. python并发编程之协程知识点

    由线程遗留下的问题:GIL导致多个线程不能真正的并行,CPython中多个线程不能并行 单线程实现并发:切换+保存状态 第一种方法:使用yield,yield可以保存状态.yield的状态保存与操作系 ...

  9. python 并发编程之协程

    一.协程 协程: 单线程下的并发,又称 微线程.协程是一种用户态的的轻量级线程,即协程是由用户程序自己控制调度的. ​ 协程的本质就是在单线程下,由用户自己控制一个任务,遇到 io 阻塞就切换另外一个 ...

  10. python并发编程之协程

    ---恢复内容开始--- 一.join方法 (1)开一个主线程 from threading import Thread,currentThread import time def walk(): p ...

随机推荐

  1. JavaWeb网上图书商城完整项目--day02-5.ajax校验功能之服务器端三层实现

    regist.jsp页面中有异步请求服务器来对表单进行校验: l  校验登录名是否已注册过: l  校验Email是否已注册过: l  校验验证码是否正确. 这说明在UserServlet中需要提供相 ...

  2. 05.DBUnit的使用

    相信做过单元测试的人都会对JUnit 非常的熟悉了,今天要介绍的DbUnit(http://dbunit.sourceforge.net/ ) 则是专门针对数据库测试的对JUnit 的一个扩展,它可以 ...

  3. 微信小程序 自定义省市选择器

    1.把省市数据放在city.js中,city.js放在until目录下 // city.js module.exports = { "province": [ { "ti ...

  4. Nacos学习笔记

    Nacos简介 Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现.服务配置.服务元数据及流量管理.Nacos 帮助更敏捷和容易地构建.交付和管理微服务平台. Nacos 是构建以“服 ...

  5. 实战笔记丨JDBC问题定位指南

    JDBC(Java数据库连接性)是Java API,用于管理与数据库的连接,发出查询和命令以及处理从数据库获得的结果集.JDBC在1997年作为JDK 1.1的一部分发布,是为Java持久层开发的首批 ...

  6. ref和out的使用及区别

    1.  ref的使用:使用ref进行参数的传递时,该参数在创建时,必须设置其初始值,且ref侧重于修改: 2. out的使用: 采用out参数传递时,该参数在创建时,可以不设置初始值,但是在方法中必须 ...

  7. JavaScript基础关于JSON(011)

    JSON意即JavaScript Object Notation,是JavaScript里数据表示的通用格式,JSON数据格式很象JavaScript里的对象: {"name": ...

  8. Python3笔记008 - 2.5 运算符

    第2章 python语言基础 运算符:是一些特殊的符号,主要用于数学计算等. 表达式:使用运算符将不同类型的数据按照一定的规则连接起来的式子. 分类:算术运算符.赋值运算符.比较运算符.逻辑运算符.位 ...

  9. Volatile关键字的解读

    原子性 定义: 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围 ...

  10. 二、web自动化快速使用

      1.启动浏览器 from selenium import webdriver # 启动谷歌浏览器,依赖:先安装好chromedriver.exe驱动 # 方式1.当chrome.driver放在p ...