协程是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. python自学之基础知识

    python学习笔记 列表的添加拓展 列表的批量添加 用for循环可以批量添加 list=['李雷雷','韩梅梅',180,110] for i in rang(3): list.append(i) ...

  2. 一个比CBitmap更优秀的类 -- CImage类

    Visual C++的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标.位图.光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP.GIF.JPEG ...

  3. JavaScript基础对象创建模式之链式调用模式(Chaining Pattern)(029)

    链式调用模式允许一个接一个地调用对象的方法.这种模式不考虑保存函数的返回值,所以整个调用可以在同一行内完成: myobj.method1("hello").method2().me ...

  4. HTML重构与网页常用工具

    下面这张思维导图,是我对全书大体内容的一个概括性总结: 工具 本书推荐的工具主要包含的是自动化测试,但是我觉得现行的开发环节当中实际用到的会比较少.这里就推荐一下其他方面的优秀工具: 1. YSlow ...

  5. 问题 C: 最短路径

    问题 C: 最短路径 在洛谷上刷最短路的题然后被老师拉回去做算法笔记上面的题... 拿到这道题,先确定所有路径唯一,然后是无向边,那么对于边权处理,直接赋值为2的k次方就可以了,然后直接跑最短路. 这 ...

  6. Layui的分页模块在网站中的应用

    制作网站的时候,有时候我们常常会被一些要求复杂的分页给困住,最后要么就是写一个简单的分页,要么就做成瀑布流的形式. 有了Layui之后,我认为开发人员多了一个选择,那就是尝试用Layui内置的分页模块 ...

  7. Electron + Websoket 通讯

    Electron + WebSocket + node.js 通信 描述 本文主要介绍了结合 Electron 和 node.js 进行 Websocket 通讯的一个简单例子. 项目结构 main. ...

  8. JVM零碎知识

    JVM常见XX参数 查看JVM默认值 常用基本配置参数 生产环境服务器变慢,如何诊断 生产环境CPU占用过高,如何诊断 JDK自带的JVM监控和性能分析工具 jps(虚拟机进程状况工具) jinfo( ...

  9. 合并两个有序链表(剑指offer-16)

    题目描述输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解答方法1:递归 /* public class ListNode { int val; List ...

  10. 浏览器如何解析css选择器?

    浏览器会『从右往左』解析CSS选择器. 我们知道DOM Tree与Style Rules合成为 Render Tree,实际上是需要将Style Rules附着到DOM Tree上, 因此需要根据选择 ...