第七章|并发编程| I/O模型

I/O模型

协程是单线程下的并发,并不是对性能都有所提升,一定是检测单个线程下的多个任务的I/O,遇到I/O不要让它阻塞,给它自动切换到其他任务去;这样就能提高单个线程下的运行效率。用gevent模块来实现了,gevent是怎么检测I/O行为的呢,遇到I/O自动切换到其他任务去。

同步异步,同步调用是提交完任务在原地等着结果拿到结果后再运行下行代码;异步调用是提交完就不管了接着往下执行,异步通常跟回调机制连用,我提交完一个任务,这个任务运行完后会自动触发回调函数运行把结果交给它。

同步不定于阻塞。

阻塞I/O

#阻塞I/O  没有并发、遇到阻塞就等着
from socket import *
from threading import Thread #可利用多线程实现并发
def communicate(conn):
    while True:
        try:
            data = conn.recv(1024) #等待
            if not data: break
            conn.send(data.upper())
        except ConnectionResetError:
            break

    conn.close()

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)

while True:
    print('starting...')
    conn, addr = server.accept()  #wait阶段主要卡在这里
    print(addr)

    t=Thread(target=communicate,args=(conn,)) #让主线程干accept的活,每来一个链接发起个线程让它干通信的活;没有解决I/O阻塞,各个运行互不影响
    t.start()                                 #线程池保证机器在健康的状态下运行

server.close()
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))
client.close()

非阻塞I/O

监测单线程下的I/O,帮你自动切换到另外一个任务

wait和copy阶段是怎么处理的呢

跟gevent一样。

from socket import *

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8083))
server.listen(5)
server.setblocking(False) #True是阻塞,False是非阻塞
print('starting...')

rlist=[]
wlist=[] #send在数据量大的情况下也会阻塞
while True:
    try:
        conn, addr = server.accept() #问操作系统有没有数据  ;服务端可以不停的建链接
        rlist.append(conn)
        print(rlist)
    except BlockingIOError: #捕捉这个异常
        #print('干其他的活') #没有数据来就可以干其他的活了,

        #收消息
        del_rlist = []
        for conn in rlist:
            try:
                data=conn.recv(1024)
                if not data:
                    del_rlist.append(conn)
                    continue
                wlist.append((conn,data.upper())) #存放套接字以及准备发的数据
            except BlockingIOError:
                continue
            except Exception:
                conn.close()
                del_rlist.append(conn)

        #发消息
        del_wlist=[]
        for item in wlist:
            try:
                conn=item[0]
                data=item[1]
                conn.send(data)
                del_wlist.append(item)
            except BlockingIOError: #
                pass

        for item in del_wlist:#发成功了把你删了
            wlist.remove(item)

        for conn in del_rlist: #把没有数据发来的conn给删除掉
            rlist.remove(conn)


server.close()
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8083))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()

多路复用I/O模型

from socket import *
import select

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8083))
server.listen(5)
server.setblocking(False)
print('starting...')

rlist=[server,] #专门存收消息的
wlist=[] #存发的数据
wdata={}

while True:
    rl,wl,xl=select.select(rlist,wlist,[],0.5) #问操作系统;[]表示出异常的
    print('rl',rl)  #rlist会不断存conn和server一堆;wlist存一堆conn,缓冲区一旦没满证明就可以发了
    print('wl',wl)  #wl是可以往缓冲区send值的这种套接字

    for sock in rl:
        if sock == server: #干链接的活
            conn,addr=sock.accept()
            rlist.append(conn)
        else:
            try:
                data=sock.recv(1024)
                if not data:  #针对linux系统
                    sock.close()
                    rlist.remove(sock) #这个套接字不要监测了
                    continue
                wlist.append(sock)
                wdata[sock]=data.upper()
            except Exception:
                sock.close()
                rlist.remove(sock) ##

    for sock in wl:
        data=wdata[sock]
        sock.send(data)
        wlist.remove(sock)
        wdata.pop(sock)

server.close()
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8083))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()

异步I/O模型

猜你喜欢

转载自www.cnblogs.com/shengyang17/p/8926235.html