一:什么是协程

  协程(Coroutine):,又称微线程。协程是一种用户态的轻量级线程。是由用户自己控制,CPU根本不知道协程存在。

  协程拥有自己的寄存器上下文和栈。

  协程调度切换时,将寄存器上下文和栈保存在其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈

  因此:协程能保留上一次调用的时的状态,每次过程重入时,就相当于进入上一次调用的。

  换种说法:进入上一次离开时所处逻辑流的位置。

  注意:线程切换会保存到CPU的寄存器里。

  协程的标准:

  1)必须在只有一个单线程里实现并发

  2)修改共享数据不需要加锁

  3)用户程序里自己保存从个控制流的上下文栈

  4)一个协程遇到IO操作自动切换到其他协程

  

二:协程在什么时候切换

  在什么时候进程切换:遇到I/O操作就切换,协程就是把io踢掉了(因为IO耗时)。

   什么时候切回去: I0操作调用完了,通过调用callback切换回去

三:协程的优点缺点

  优点:

  1)无需线程上下文切换的开销

  2)无需原子操作锁定及同步的开销(因为协程就是单线程,它就是串行,同一时间改数据只有一个线程)

  3)方便切换控制流,简化编程模型

  4)高并发+高扩展性+低成本:一个CPU支持上万的协程不是问题,很适合高并发

  缺点:

  1)无法利用多核资源:协程本质是单线程,他不能同时单个CPU的多个核用上,协程需要和进程配合

    才能运行在多CPU上。

  2)进行阻塞(Blocking)操作(如IO时)会阻塞整个程序

四:yield实现切换

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun' import time
import queue def consumer(name):
print("------->starting eating baozi...") while True:
new_baozi=yield
print("[%s] is eating baozi %s" %(name,new_baozi)) def producer():
r=con.__next__() #con=consumer("c1")#只是生成生成器,不会执行,所以先要调用next才会开始执行
r=con2.__next__() n=0 while n <5:
n+=1
con.send(n)#两个作业,唤醒生成器,并赋值
con2.send(n) print("\033[32;1m[producer]\033[0m is making baozi %s" %n) if __name__=='__main__':
con=consumer("c1") #生成生成器
con2=consumer("c2")
p=producer() """
------->starting eating baozi...
------->starting eating baozi...
[c1] is eating baozi 1
[c2] is eating baozi 1
[producer] is making baozi 1
[c1] is eating baozi 2
[c2] is eating baozi 2
[producer] is making baozi 2
[c1] is eating baozi 3
[c2] is eating baozi 3
[producer] is making baozi 3
[c1] is eating baozi 4
[c2] is eating baozi 4
[producer] is making baozi 4
[c1] is eating baozi 5
[c2] is eating baozi 5
[producer] is making baozi 5
"""

  我们刚才用yield实现一个简单的协程,实现单线程多并发。

五:Greenlet

  greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun' from greenlet import greenlet def test1():
print(12)
gr2.switch()
print(34)
gr2.switch() def test2():
print(56)
gr1.switch()
print(78) gr1=greenlet(test1)#起动一个协程
gr2=greenlet(test2)
gr1.switch() #从test1开始

  上面代码切换过程

  

  没有解决一个问题,就是遇到IO操作,自动切换,手动切换。下面实现自动切换

六:Gevent

   Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet,  

  它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun' import gevent def func1():
print("\033[31;1m 李在搞锗\033[0m")
gevent.sleep(2)#遇到sleep自动切换,模拟IO操作
print("\033[31;1m 李在又继续搞锗。。。。\033[0m") def func2():
print(("\033[32;1m 李切换搞牛。。。\033[0m"))
gevent.sleep(1)#遇到sleep自动切换
print(("\033[32;1m 李切换继续搞牛。。。\033[0m")) gevent.joinall(
[
gevent.spawn(func1),#可以带多个参数,第一个为函数名,第二个为函数参数
gevent.spawn(func2)
]
) """
李在搞锗
李切换搞牛。。。
李切换继续搞牛。。。
李在又继续搞锗。。。。
"""

七: 同步与异步的性能区别

# -*- coding:utf-8 -*-
__author__ = 'shisanjun' import gevent def task(pid):
gevent.sleep(0.5)
print('Task %s done' %pid) def synchronous():
for i in range(1,10):
task(i) def asynchronous():
theads=[gevent.spawn(task,i) for i in range(10)]
gevent.joinall(theads) print("synchronous")
synchronous() #顺序执行,结果是一个个出来
print("asynchronous")
asynchronous() #并发执行,结果几乎同时出来 """
synchronous
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
asynchronous
Task 0 done
Task 9 done
Task 8 done
Task 7 done
Task 6 done
Task 5 done
Task 4 done
Task 3 done
Task 2 done
Task 1 done """

  上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn

   初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,  

  后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在 所有greenlet执行完后才会继续向下走

  

八:自动遇到IO切换

  

Gevent 默认不知道urllib,socket做了IO操作,所以打补厅,增加monkey.patch_all()
# -*- coding:utf-8 -*-
__author__ = 'shisanjun' from gevent import monkey
import gevent
from urllib.request import urlopen
#gevent默认检测不到ulrlib,所以默认是阻塞的,要加monkey实现自动切换
monkey.patch_all()#实现遇到IO就自动切换 def f(url):
print('Get %s '%url)
resp=urlopen(url)#这里自动切换了 data=resp.read()
print("%d bytes received from %s." %(len(data),data)) gevent.joinall([
gevent.spawn(f,"https://www.baidu.com"),
gevent.spawn(f,"https://www.360.cn"), ])

九:通过gevent实现单线程下的多socket并发

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun'
import sys
import socket
import time
import gevent from gevent import socket,monkey monkey.patch_all() def server(port):
s=socket.socket()
s.bind(("0.0.0.0",port))
s.listen(100) while True:
conn,addr=s.accept()
gevent.spawn(handle_request,conn) def handle_request(conn):
try:
while True:
data=conn.recv(1024)
print('recv:',data)
conn.send(data)
if not data:
conn.shutdown(socket.SHUT_WR)
except Exception as e:
print(e)
finally:
conn.close() if __name__=="__main__":
server(8001)
# -*- coding:utf-8 -*-
__author__ = 'shisanjun'
import socket
import threading def sock_conn(): client = socket.socket() client.connect(("localhost",8001))
count = 0
while True:
#msg = input(">>:").strip()
#if len(msg) == 0:continue
client.send( ("hello %s" %count).encode("utf-8")) data = client.recv(1024) print("[%s]recv from server:" % threading.get_ident(),data.decode()) #结果
count +=1
client.close() for i in range(100):
t = threading.Thread(target=sock_conn)
t.start() #并发100个sock连接

本文没有解决:什么时候切换回来

python网络编程-协程(协程说明,greenlet,gevent)的更多相关文章

  1. Python网络编程Socket之协程

    一.服务端 __author__ = "Jent Zhang" import socket import gevent from gevent import monkey monk ...

  2. python并发编程之线程/协程

    python并发编程之线程/协程 part 4: 异步阻塞例子与生产者消费者模型 同步阻塞 调用函数必须等待结果\cpu没工作input sleep recv accept connect get 同 ...

  3. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  4. python网络编程知识体系

    python的网络编程包括: 1.mvc-socket-线程-进程-并发-IO异步-消费者生产者 2.mysql-paramiko-审计堡垒机-redis-分布式监控 线程.进程 和 协程 原理剖析 ...

  5. python 网络编程:socket

    在学习socket之前,我们先复习下相关的网络知识. OSI七层模型:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层.OSI七层模型是由国际标准化组织ISO定义的网络的基本结构,不仅包括一 ...

  6. 图解Python网络编程

    返回目录 本篇索引 (1)基本原理 (2)socket模块 (3)select模块 (4)asyncore模块 (5)asynchat模块 (6)socketserver模块 (1)基本原理 本篇指的 ...

  7. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  8. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  9. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  10. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

随机推荐

  1. 洛谷 P1783 海滩防御 解题报告

    P1783 海滩防御 题目描述 WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和仓库总是被敌方派人偷袭 ...

  2. 【bzoj3122】 Sdoi2013—随机数生成器

    http://www.lydsy.com/JudgeOnline/problem.php?id=3122 (题目链接) 题意 对于一个数列${X_i}$,其递推式为:${X_{i+1}=(a*X_i+ ...

  3. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  4. UVA.12169 Disgruntled Judge ( 拓展欧几里得 )

    UVA.12169 Disgruntled Judge ( 拓展欧几里得 ) 题意分析 给出T个数字,x1,x3--x2T-1.并且我们知道这x1,x2,x3,x4--x2T之间满足xi = (a * ...

  5. Web项目开发中用到的缓存技术

    在WEB开发中用来应付高流量最有效的办法就是用缓存技术,能有效的提高服务器负载性能,用空间换取时间.缓存一般用来 存储频繁访问的数据 临时存储耗时的计算结果 内存缓存减少磁盘IO 使用缓存的2个主要原 ...

  6. 21天实战caffe笔记_第二天

    1 传统机器学习 传统机器学习:通过人工设计特征提取器,将原始数据转化为合适的中间表示形式或者特征向量,利用学习系统(通常为分类器)可以对输入模式进行检测或者分类.流程如下: 传统机器学习的局限在于需 ...

  7. web项目中的执行流程参数传递详解

    还是从这个图开始讲解: struts2中有一个存放数据的中心:值栈.(值栈里面有map和对象栈) 首先:值栈的作用范围是一个请求:request作用域(一个请求是代表的一个过程,即页面点击到数据返回到 ...

  8. Zabbix应用四:Zabbix监控Nginx

    利用Zabbix监控Nginx 一.准备nginx监控模版: 1.1.下载nginx监控模版:  点此下载 1.2.导入模版: Zabbix管理页面,选择'配置'->'模版'->'导入': ...

  9. 使用 Dojo 掌握面向对象开发

    原文出处:Joe Lennon 从头开始学习 Dojo,第 2 部分 使用 Dojo 掌握面向对象开发 什么是面向对象开发? 面向对象编程(Object-Oriented Programming,OO ...

  10. Java基础-IO流对象之File类

    Java基础-IO流对象之File类 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.IO技术概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下 ...