什么是协程

协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程

协程的特点

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的优点

  • 无需线程上下文切换的开销
  • 无需原子操作锁定及同步的开销

    "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。(因为携程只有一个线程)

  • 方便切换控制流,简化编程模型
  • 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。(一个进程一个携程,而携程又可以开多个携程,CPU一个核心开一个进程)

协程的缺点

  • 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  • 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序 (携程类似以一个管道,如果一个地方堵住了,那么整个就不通了)

最底层的协程

使用yield实现协程操作例子

一个服务端在创建,而两个客户端在接收。在单线程上几乎同时执行,代码如下:

#客户的方法
def customer(name):
print("===准备买东西===")
while True:
ret = yield
print("名字:%s,买了:%s"%(name,ret)) #服务端
def produce(num):
next(cus1)
next(cus2)
values = 0
while values < num:
values +=1
cus1.send(values)
cus2.send(values) print("谢谢惠顾") if __name__ == "__main__":
cus1 = customer("小明") #创建2个客户端方法的对象
cus2 = customer("小白") produce(5)
#运用生成器的,yield,send,next的特性就可以弄一个最简单的协程

  

Python内部来实现协程的模块gevent

gevent模块不属于Python标准库的模块,要的话得自己下载。下面就让我们看看怎么下载。

我们也可以用greenlet模块实现的协程

greenlet模块也是刚刚在下载gevent模块才有的模块。from greenlet import greenlet ,创建协程对象的方法其实有2个参数“greenlet(run=None,parent = None)”。参数“run”就是要调用的方法,比如下例子中的t1,t2,参数“parent”定义了该协程的父协程,也就是说,greenlet协程直接是可以有父子关系的。如果不设或设为空,则其父协程就是程序默认的“main”主协程。而在要调用的方法,如下面的t1对象中,有一个重要的方法t1.switch(),这个方法的意思就是暂停当前的方法,切换到t1。

实例如下代码

from greenlet import greenlet   #调用模块中的方法

def fun1():
print('a')
t2.switch()
print('b') def fun2():
print('c')
t1.switch()
print('d') t1 = greenlet(fun1) #创建greenlet对象
t2 = greenlet(fun2) t1.switch() #执行t1 #我们可以看到只执行了acb,d并没有执行,因为fun1后面还少了个switch()
#所以可以看出switch还有暂停作用

  

Gevent下所支持的协程

在讲这个之前引进一个内容

猴子补丁 Monkey patching

了实现网络通信的高并发,但是,Gevent直接修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行。但是我们无法保证你在复杂的生产环境中有哪些地方使用这些标准库会由于打了补丁而出现奇怪的问题。

一种方法是使用gevent下的socket模块,我们可以通过”from gevent import socket”来导入。不过更常用的方法是使用猴子布丁(Monkey patching)。使用猴子补丁褒贬不一,但是官网上还是建议使用”patch_all()”,而且在程序的第一行就执行。猴子补丁也在Gevent模块的方法中。

Gevent 实现了异步I/O的协程,也就是说只有在遇到I/O阻塞的时候才能切换到其他的方法,而这个I/O阻塞即是可以是执行代码的偶然,也可以是我们定义的必然。

import gevent 这个gevent模块

在看代码之前要知道gevent方法这个对象中的几个方法:

spawn(func,func_args)  func:加入要实现gevent的方法的名字,func_args:方法要传入的参数    创建协程实例

joinall([spawn_list,])    spawn_list:添加入我们刚刚创建的gevent对象              类似于一个同时启动

sleep(time)       time:时间(秒)                           交出CPU控制权限,时间为秒,类似于一个I/O阻塞。这里不能用time.sleep代替

getcurrent()                                         获取当前协程内存地址

下面就让我们来看看例子:

from gevent import monkey   #引入monkey方法

import gevent,time

monkey.patch_all()      #这个在小的协程中体现不出效果,不过建议加下。养成个习惯

def a():
print("1")
gevent.sleep(2) #模拟I/O阻塞2秒
print("2") def b():
print("3")
gevent.sleep(1)
print("4") start = time.time()
gevent.joinall([ #这里必须是个列表
gevent.spawn(a),
gevent.spawn(b),
]
) print(time.time()-start)
#这里可以看到实际上才执行了2秒多一点

  

Python 协程 61的更多相关文章

  1. Python 协程总结

    Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...

  2. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  3. 终结python协程----从yield到actor模型的实现

    把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...

  4. 从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 ...

  5. 关于python协程中aiorwlock 使用问题

    最近工作中多个项目都开始用asyncio aiohttp aiomysql aioredis ,其实也是更好的用python的协程,但是使用的过程中也是遇到了很多问题,最近遇到的就是 关于aiorwl ...

  6. 用yield实现python协程

    刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...

  7. [转载] Python协程从零开始到放弃

    Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC   2017-10-09  3,973   Author: lightless@Meili-inc Date: 2017100 ...

  8. 00.用 yield 实现 Python 协程

    来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...

  9. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

随机推荐

  1. 用word发CSDN blog,免去插图片的烦恼

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  2. 导出文件的时候 加大php内存

    ini_set('max_execution_time', 3600); ini_set('memory_limit', '2048M');

  3. Linux系统中无iptables文件的解决

    在RHEL 7 / CentOS 7中,firewalld被引入来管理iptables,CentOS7开始,默认是没有iptables的,而是使用firewall防火墙.本文将屏蔽掉firewall, ...

  4. PhoenixFD插件流体模拟——UI布局【Input】详解

    Liquid Input 流体输入 本文主要讲解Input折叠栏中的内容.原文地址:https://docs.chaosgroup.com/display/PHX3MAX/Liquid+Input 主 ...

  5. [Solution] 969. Pancake Sorting

    Difficulty: Medium Problem Given an array A, we can perform a pancake flip: We choose some positive ...

  6. 2019 年 React 学习路线图(转)

    转自:https://www.infoq.cn/article/AEkiVAiJf25LZmoUe_yc 之前我们已经介绍了2019 年 Vue 学习路线图,而 React 作为当前应用最广泛的前端框 ...

  7. java 诊断工具——Arthas

    该说不说!小编做的这些功能,最讨厌的就是优化!某些前辈大佬写的代码小辈我实在不敢恭维!那逻辑!那sql! 接下来!今天的主角就登场了,阿里巴巴最近开源出来的一个针对 java 的工具,主要是针对 ja ...

  8. 简单的页面互点Javascript代码

    简单的页面互点Javascript代码,可以适用于前端$(function(){ $('.ip_b_con_item li,.pro_index_list li').mouseover(functio ...

  9. HDU - 1695 GDU

    莫比乌斯反演基础. 用rep 去掉重复的对数,rep一定是奇数( 因为有(1,1 ) ) #include <bits/stdc++.h> using namespace std; #de ...

  10. (3)Linux的哲学思想

    1. 一切皆文件 把几乎所有资源统统抽象为文件形式,包括硬件设备,甚至通信接口等,便于统一管理和定义: 对文件的操作有:open,read,write,close,delete,create 2. 由 ...