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

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模型

相关文章: