day39
IO操作主要包括两类:
本地IO:本地IO是指本地的文件读取等操作,本地IO的优化主要是在操作系统中进行,我们对于本地IO的优化作用十分有限
网络IO:网络IO指的是在进行网络操作时需要等待用户的输入及传输的等待等,网络IO的优化需要我们自己进行,而我们对于网络IO的优化主要在等待用户输入时程序可以继续运行
1).多线程或多进程,
当客户端并发量非常大的时候,服务器可能就无法开启新的线程或进程,如果不对数量加以限制 服务器就崩溃了
2)线程池或进程池
首先限制了数量 保证服务器正常运行,但是问题是,如果客户端都处于阻塞状态,这些线程也阻塞了
3)
使用一个线程处理所有客户端,当一个客户端处于阻塞状态时可以切换至其他客户端任务
如何使用:
将server的blocking设置为False 即设置非阻塞
存在的问题 :
这样一来 你的进程 效率 非常高 没有任何的阻塞
很多情况下 并没有数据需要处理,但是我们的进程也需要不停的询问操作系统 会导致CPU占用过高
3.案例:
服务端:
import socket
import time
server = socket.socket()
server.bind(("127.0.0.1",1688))
server.listen()
server.setblocking(False) # 默认为阻塞 设置为False 表示非阻塞
# 用来存储客户端的列表
clients = []
# 链接客户端的循环
while True:
try:
client,addr = server.accept() # 接受三次握手信息
# print("来了一个客户端了.... %s" % addr[1])
# 有人链接成功了
clients.append(client)
except BlockingIOError as e:
# print("还没有人连过来.....")
# time.sleep(0.5)
# 服务你的客人去
for c in clients[:]:
try: # 可能这个客户端还没有数据过来
# 开始通讯任务
data = c.recv(2048)
c.send(data.upper())
except BlockingIOError as e:
print("这个客户端还不需要处理.....",)
except ConnectionResetError:
# 断开后删除这个客户端
clients.remove(c)
print("=======================",len(clients))
客服端:
import socket
client = socket.socket()
client.connect(("127.0.0.1",1688))
while True:
msg = input("msg:").strip()
if not msg:
continue
try:
client.send(msg.encode("utf-8"))
recv_msg = client.recv(2048)
print(recv_msg.decode("utf-8"))
except ConnectionResetError:
print("客户端意外关闭")
break
多路复用的缺点:
使用多路复用解决了在非阻塞IO中出现的CPU占用过高的问题,但是在多路复用中也出现了几个问题:
-
使用select时最多只能处理1024个客户端,如果数量多与此值,那么就会直接就会报错
-
如果发送的数据量特别大的情况下只能处理一个客户端,其它的客户端只能进行等待

浙公网安备 33010602011771号