---恢复内容开始---

gevent

1、切换+保存状态
2、检测单线程下任务的IO,实现遇到IO自动切换

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

#用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数
,可以是位置实参或关键字实参,都是传给函数eat的 g2=gevent.spawn(func2) g1.join() #等待g1结束 g2.join() #等待g2结束 #或者上述两步合作一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值

遇到IO阻塞时会自动切换任务

#初识gevent
import gevent
def task():
print('aaa')
gevent.sleep(3)# 当遇到io 时 不会等,会切到task1,然后执行task1的代码,然后又遇到IC再切回来
#回来一看还在睡,然后再切到task1 来回切直到有一个睡醒了就行了
print('cccc')
def task1():
print('aaa')
gevent.sleep(2)
print('cccc') t1=gevent.spawn(task,)
t2=gevent.spawn(task1,)
t1.join()
t2.join()
print('zhu')

上例gevent.sleep(2)模拟的是gevent可以识别的io阻塞,

而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了

from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前

或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头

from gevent import monkey,spawn;monkey.patch_all()  #这个模块的引入一定要放在最上边
#因为socket
from socket import *
import time
#from threading import Thread
def server(ip,cont):
server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind((ip,cont))
server.listen(5)
while True:
print('aaa')
time.sleep(0.1)
print('bbb')
conn,addr=server.accept()# 因为接受的过程中会有IO
# (即是accept 在等 wait data 和data copy这两个过程)
#然后就会去切到task 函数 task 函数如果没有内容就会切回来来回切换
#这样减少了等待,提高了效率,(相当与单线程下实现并发)
spawn(task,conn,) # 实现了单线程下的并发,因为这里是新开了一个函数
# 而不是新开了一个线程或者进程,所以这样弄节省内存空间
def task(conn):
while True:
print('ccc')
try:
data=conn.recv(1024)
if not data:continue
conn.send(data.upper())
except ConnectionResetError:
conn.close() if __name__ == '__main__':
server('127.0.0.1',8090)
#1 对cpu的占用率过多,但是是无用的占用
#2 在连接数过多的情况下,不能及时响应客户的的消息
from socket import *
import time
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8090))
server.listen(5)
server.setblocking(False)#设置为
conn_l=[] #将conn 加到列表中,让下一列用
while True:
try:
conn,addr=server.accept()
conn_l.append(conn)
print(addr)
except BlockingIOError:
print('去干其他活儿了',len(conn_l))
del_l=[]
for conn in conn_l: #在这里用例表中存入的内容
try:
data=conn.recv(1024)
if not data:
del_l.append(data) #如果是空的放到问题项列表中,
continue conn.send(data.upper())
except BlockingIOError:
pass
except ConnectionResetError:
conn.close() #关闭conn
del_l.append(conn)
for i in del_l:
conn_l.remove(i) #删除有问题的内容。

非阻塞IO模型

socketserver模块

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):#定义一个类继承他得使用他的规则
def handle(self): #处理通信的活儿
print('=====>',self)#self.request==conn 他们两个是等价的意思
print(self.request) #打印的内容为<socket.socket fd=452, family=AddressFamily.AF_INET,
# type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080),
# raddr=('127.0.0.1', 63347)> 他是套接字对象,等价于conn 包含recv方法
while True:
data=self.request.recv(1024)
self.request.send(data.upper()) if __name__ == '__main__':
# socketserver.ForkingTCPServer linux的用这个
server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler)
server.serve_forever() #以上的代码等价于如下的操作,建立连接,相当于把他封装在了这个对象中
# while True:
# conn,addr=server.accept()
# t=Thread(target=func,args=(conn,))
# t.start()

 SocketServer 模块  重要*****

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。

#tcp 服务端
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):#定义一个类继承他得使用他的规则
def handle(self): #处理通信的活儿
print('=====>',self)#self.request==conn 他们两个是等价的意思
print(self.request) #打印的内容为<socket.socket fd=452, family=AddressFamily.AF_INET,
# type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080),
# raddr=('127.0.0.1', 63347)> 他是客户端的套接字对象,等价于conn
# 包含recv方法
while True:
data=self.request.recv(1024)
self.request.send(data.upper()) if __name__ == '__main__':
# socketserver.ForkingTCPServer linux的用这个
server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler)
#??
server.serve_forever() #循环的建链接, #以上的代码等价于如下的操作,建立连接,相当于把他封装在了这个对象中
# while True:
# conn,addr=server.accept()
# t=Thread(target=func,args=(conn,))
# t.start()
#UDP服务端
import socketserver
class MyUDPhandler(socketserver.BaseRequestHandler):
def handle(self):
print(self.request)#(b'ss', <socket.socket fd=408,
# family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM,
# proto=0, laddr=('127.0.0.1', 8080)>)
#打印出来的是一个元祖, 第一个值是收到客户端发送的信号,第二个值是
#服务端---套接字对象
client_data=self.request[0] #cclient_data 这个格式是固定的,不要改变它
self.request[1].sendto(client_data.upper(),self.client_address)#client_address 这个是他自己有的
if __name__ == '__main__':
server=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPhandler)
server.serve_forever()

I/O多路复用
Linux中的 select,poll,epoll 都是IO多路复用的机制。I/O多路复用指:通过一种机制,可以监视多个描述符

一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

#select 的功能只是监测套接字有没有数据,不负责取
from socket import *
import time
import select
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8090))
server.listen(5)
server.setblocking(False)#设置为
read_l=[server,] #初始状态加server, 初始状态要对这个套接字对象进行监控,
# 当不阻塞时(即有客户端连过来的)select
while True:
r1,w1,x1=select.select(read_l,[],[])##read_l=[server,conn1,conn2,conn3]
# 里边要传入三个参数,
# 当要用那个的时候传入对应的列表,要监控读时要在第一个
# 不用的传入空列表
#r1[]列表中只寸准备好的套接字
#print(r1[0] is server)# r1[0]是一个套接字对象 服务端
for r in r1:#循环列表,将里边准备好的内容执行,实现并发的效果
if r is server: #判断好了的对象是 server 还是conn
conn,addr=r[0].accept()
print(addr)
read_l.append(conn)
else: #如果是conn就执行这些代码
try:
data=r.recv(1024)
if not data:
r.close()
read_l.remove(r)
r.send(data.upper())
except ConnectionResetError:
r.close()
read_l.remove(r)
 

 

day36 python学习gevent io 多路复用 socketserver *****的更多相关文章

  1. python day 15: IO多路复用,socketserver源码培析,

    目录 python day 15 1. IO多路复用 2. socketserver源码分析 python day 15 2019/10/20 学习资料来自老男孩教育 1. IO多路复用 ''' I/ ...

  2. python学习之-- IO多路复用 select模块

    python I/O多路复用包括3个模块,上一篇已经说过概念,这里我使用的是select模块实现一个ftp并发 服务器端核心代码: import socket,select import queue, ...

  3. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...

  4. python网络编程——IO多路复用之select

    1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...

  5. socket_server源码剖析、python作用域、IO多路复用

    本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...

  6. python中的IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  7. Python实战之IO多路复用select的详细简单练习

    IO多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. select   它通过一个select()系统调用来 ...

  8. python之路 IO多路复用 线程进程初步了解

    一.IO多路复用 1.客户端 #!/usr/bin/env python #-*-coding:utf-8-*- import socket sk=socket.socket() sk.connect ...

  9. Python自动化之IO多路复用

    单线程.多线程和异步对比图 灰色的是阻塞 IO多路复用 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心 ...

随机推荐

  1. Java 本地环境设置

    如果你希望在你的本地环境中设置 Java 程序环境,下面的这部分将会指导你在你的本地计算机上下载和设置 Java 环境.你可以按照下面的步骤进行. Java SE 目前是免费下载的,你可以通过单击下面 ...

  2. BZOJ-1010 玩具装箱toy (斜率优化)

    题目大意:将n个数分成若干组,并且每组的数在原数组中应是连续的,每组会产生的代价为sum(i)-sum(j)+i-j-1-m,m为已知的常数.求最小代价. 题目分析:定义dp(i)表示将前 i 个元素 ...

  3. Oracle 声明常量 (转)

    原文地址 Oracle 声明常量 常量在声明时赋予初值,并且在运行时不允许重新赋值.使用CONSTANT关键字声明常量. 声明常量 DECLARE pi CONSTANT number :=3.14; ...

  4. ps -ef |grep xxx 输出的具体含义

    ps:将某个进程显示出来 -A 显示所有程序. -e 此参数的效果和指定"A"参数相同. -f 显示UID,PPIP,C与STIME栏位. grep命令是查找 中间的|是管道命令 ...

  5. VC++ 报错:Heap corruption detected

    今天在写代码时,发现莫名其妙的错误: std::string strName = L“testtest”; char* pOutString = new char(len + 1); Decrypt( ...

  6. 071——VUE中vuex之使用getters计算每一件购物车中商品的总价

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. jsp jsp属性范围

    jsp提供了4中属性分别是 当前页:一个属性只能在一个页面中取得,跳转淘其他页面无法取得. 一次服务器请求:一个页面中设置的属性,只要经过了服务跳转,而跳转之后的页面可以继续取得 一次回话:一个用户设 ...

  8. 离线部署 Cloudera Manager 5 和 CDH 5.12.1 及使用 CDH 部署 Hadoop 集群服务

    Cloudera Manager Cloudera Manager 分为两个部分:CDH和CM. CDH是Cloudera Distribution Hadoop的简称,顾名思义,就是cloudera ...

  9. 网络协议栈学习(二)创建 socket

    下面通过学习linux 1.2.13源码进一步理解socket通信机制.对该版本源码的学习主要参考<Linux内核网络栈源代码情景分析>(曹桂平 编著). 要理解socket的本质,就要理 ...

  10. C++设计模式之访问者模式

    简述 访问者模式(Visitor Pattern)表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 代码实现: // Visitor.cpp : ...