协程是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网上图书商城完整项目--11.项目所需jquery函数介绍

    1.下载jquery的函数包 2.强函数包添加到工程的web-root目录下 3.在jsp文件中加载js文件 <script type="text/javascript" s ...

  2. 【原创】Linux中断子系统(四)-Workqueue

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  3. vue全家桶(3.1)

    4.数据请求 4.1.axios是什么? axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它有以下特征: 从浏览器中创建 XMLHttpRequest 从 no ...

  4. Linux中的block容量

    block容量的大小直接关系到文件系统存储使用是否合理的问题: 因为每个block只能供一个文件使用,所以如果Linux系统的block容量太大,但系统经常存储的都是小文件那么会很浪费系统磁盘: 但如 ...

  5. 一个ACE 架构的 C++ Timer

    .h #ifndef _Timer_Task_ #define _Timer_Task_ #pragma once #include <ace/Task.h> #include <a ...

  6. 让MySQL为我们记录执行流程

    让MySQL为我们记录执行流程   我们可以开启profiling,让MySQL为我们记录SQL语句的执行流程   查看profiling参数 shell > select @@profilin ...

  7. Aaronson,又是思维题

    题目: Recently, Peter saw the equation x0+2x1+4x2+...+2mxm=nx0+2x1+4x2+...+2mxm=n. He wants to find a ...

  8. mysql根据逗号分割的字符串去关联查询另外一个表的数据

    1.说明 在做显示数据的时候,一个字段会存那种逗号分割的字符串,那如何去根据逗号分割字符串去查询另一个表的数据呢? 首先我们查看一下需要显示的数据 select * from company wher ...

  9. List的isEmpty与==null的区别

    集合的判空一般判定方法 ArrayList<Person> list = null; System.out.println(null == list);//return true Syst ...

  10. day38 并发编程(理论)

    目录 一.操作系统发展史 二.多道技术 1 单核实现并发的效果 2 多道技术图解 3 多道技术重点 三.进程理论 1 必备知识点 2 进程调度 3 进程的三状态 4 两对重要概念 四.开启进程的两种方 ...