线程 四
2021-04-08 本文已影响0人
吃可爱长大鸭
目录
1.内容
2.多路复用
3.非阻塞IO
1.内容
IO 模型
什么是IO 指的是输入输出,其执行速度都非常慢
模型,指固定的套路
IO模型 就是 所有可以实现输入输出的套路
IO的分类
1.本地IO 指的是输入输出到本地计算机 比如写入硬盘
2.网络IO 指的是输入输出到 网络中的计算机 速度远比本地IO慢(*****)
网络IO的输入输出过程
IO模型(******):
1.阻塞型IO
之前学习的IO操作处理gevent都是阻塞型的
1.可以利用多线程来提高效率
线程数量不能太多 会造成内存溢出
2.线程池可以解决线程太多的问题
但是如果线程池数量达到最大 其他客户端将进入等待
3.在单线程并发的来处理 可以使单核下的效率最高
2.非阻塞IO
3.多路复用
4.异步IO
2.多路复用
多路复用
指的是
多个连接在复用一个线程
反过来说 一个线程处理多个连接
提高了单线程处理能
多路复用提升的 单线程处理网络IO的效率
协程提升的是 单线程处理所有IO的效率
######client
import socket
import os
import time
c = socket.socket()
c.connect(("127.0.0.1",21211))
while True:
msg = "hello i am: %s" % os.getpid()
time.sleep(1)
if not msg:
continue
c.send(msg.encode("utf-8"))
print(c.recv(1024).decode("utf-8"))
####server
import socket
import select
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()
# server.setblocking(False)
# select 是帮我们监控连接
# 需要给它传两个列表 一个是检测是否可读(是否可以执行recv) 一个是检测是否可写(是否可执行send)
rlist = [server,]
wlist = []
# 存储要发送的数据
msg = {}
# 默认select是阻塞的 会直到有其中一个或几个需要被处理
# 返回值
# 1.可读的连接(可以执行recv)
# 2.可写的连接(可以执行send)
while True:
readable_list,writeable_list,_ = select.select(rlist,wlist,[])
# 接下来就是要处理这些可读可写列表
print(readable_list)
# 处理可读列表
for c in readable_list:
if c == server: # 说明当需要被处理的是服务器
client,addr = c.accept()
# 把客户端也交给select来检测
rlist.append(client)
else:
print("客户端可以recv啦!")
data = c.recv(1024)
print(data.decode("utf-8"))
# 给客户端返回数据
# c.send(data.upper())
wlist.append(c) # 将客户端也交给select检测是否可写
msg[c] = data
print(writeable_list)
print(msg)
# 处理可写列表
for w in writeable_list:
w.send(msg[w].upper())
# 将已经发送完成的连接从 检测列表删除
wlist.remove(w)
3.非阻塞IO
####client
import socket
import os,time
c = socket.socket()
c.connect(("127.0.0.1",21211))
while True:
msg = "hello i am: %s" % os.getpid()
time.sleep(1)
if not msg:
continue
c.send(msg.encode("utf-8"))
print(c.recv(1024).decode("utf-8"))
####server
import socket,time
from time import sleep
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()
server.setblocking(False)
# 保存所有的客户端
clients = []
# 需要发送的数据
msg_ls = []
while True:
# 需要接收三次握手数据 所以也是一个阻塞 必须经历wait 和 copy
try:
client,addr = server.accept()
print("来了一个客户端....")
# 每次执行到这个代码的时候 client的值都是一个新的值 则意味只能处理本次的新的客户端
# while True:
# client.send(client.recv(1024).upper())
clients.append(client)
except BlockingIOError:
# sleep(0.1) #
print("还没有数据可以处理 那就干别的事情去")
# 执行except 说明服务器没有请求可以处理 可以去处理客户端通讯
# 已经关闭的 需要删除的客户端
close_ls = []
# 接收数据的循环
for c in clients:
try:
data = c.recv(1024)
if not data:
c.close()
close_ls.append(c)
continue
# 不能直接发 因为操作系统缓存如果满了 会抛异常
# c.send(data.upper())
msg_ls.append((c,data))
except BlockingIOError:
pass
except ConnectionResetError:
c.close()
close_ls.append(c)
# 遍历完成后 删除关闭的连接
for i in close_ls:
clients.remove(i)
close_ls.clear()
# 发送数据的循环
# 保存已经发送过的数据
rm_msg = []
for i in msg_ls:
try:
i[0].send(i[1].upper())
rm_msg.append(i)
print("发送成功!")
except BlockingIOError:
print("发送失败!")
# 清理已经发送过的数据!
for msg in rm_msg:
msg_ls.remove(msg)
rm_msg.clear()
####server2
import socket
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()
server.setblocking(False)
# all clients
clients = []
while True:
try:
client,addr = server.accept()
clients.append(client)
except BlockingIOError:
# 存储所有已经关闭的客户端
close_ls = []
# 存储所有需要发送数据的客户端和数据
msg_ls = []
for c in clients:
try:
data = c.recv(1024)
if not data:
c.close()
close_ls.append(c)
# 把要发送数据的 客户端 和数据存储到列表中 单独发送
msg_ls.append((c,data))
except BlockingIOError:
pass
except ConnectionResetError:
c.close()
close_ls.append(c)
# 处理发送数据
# 已经发送完成的客户端和数据
sended_msg = []
for client_and_data in msg_ls:
c = client_and_data[0]
data= client_and_data[1]
try:
c.send(data.upper())
# 加入待删除列表
sended_msg.append(client_and_data)
except BlockingIOError:
pass
# 将已经发送成功的数据从待发送列表中删除
for i in sended_msg:
msg_ls.remove(i)
sended_msg.clear()
# 把已经关闭的连接从 所有客户端列表中删除
for i in close_ls:
clients.remove(i)
close_ls.clear()