您的位置:首页 > 编程语言

并发编程---IO模型

2020-02-01 00:59 627 查看

IO模型

任务的提交方式有两种:

  • 同步:应用程序提交完任务,等待结果结果,之后在执行下一个任务
  • 异步:应用程序提交完任务,继续执行不等待结果,任务执行完,会自动出发异步中的会带哦函数

同步不等于阻塞:

  • 同步:提交任务完,不管任务有没有遇到阻塞,只等待接收结果,任务运行完,才接着往下走
  • 阻塞:提交任务的时候遇到IO,没有处理的话,操作系统就会抢走CPU。解决方法:使用gevent,检测到IO的时候,就切换到其他任务

IO模型的主要分类:

  • 阻塞IO           blocking IO
  • 非阻塞IO       nonblocking IO
  • IO多路复用   IO multiplexing
  • 信号驱动IO   signal driven IO 
  • 异步IO          asynchronous IO

遇到IO会阻塞:卡在原地; 网络IO:原地阻塞

1.server端什么样得操作属于IO行为    

  • 服务端的accept,recv,send,
  • 其中accept,recv会感觉明显的等,
  • send 不会明显等,但也是IO行为

2.为什么IO行为会让有在原地等待的效果

      由于server在recv的时候 会有一个等待的时间,就是等待操作系统缓存中存在数据,才copy到用程序当中

阻塞IO

import socket
from threading import Thread

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

def communicate():
while True:
try:
data = conn.recv(1024)
print('接收的数据:' ,data)
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()

print('setting...')
while True:
print('settings')
conn,client_addr = server.accept() # io阻塞,操作系统拿走了cpu
print(client_addr)

t = Thread(target=communicate,args=(conn,))
t.start()

server.close()
服务端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
cmd = input('>>:').strip()
if not cmd:continue
client.send(cmd.encode('utf-8'))
data = client.recv(1024)
print(data)
phone.close()
客户端

非阻塞IO

应用程序自己检测io,遇到io就切给其他的任务,这样可以使单线程的效率大大提高

存在的问题:

  • cpu在做其他的事情时候,传来了数据,不会立即响应
  • 服务端没有任何的阻塞,就是死循环,cpu会一直的运转,进程处于就绪状态,这样大量占用cpu,让应用程序一直向操作系统询问数据好没好,在做着无用功

多路复用IO

阻塞io: 有wait()等待过程,copy过程,

多路复用io: 比阻塞io多了一个select过程,这个过程可以作为中介,询问操作系统有没有数据

  • 缺点:只有一个套接字的时候比阻塞io性能低,当监测多个套接字的时候,循环慢,列表数据多的话,效率低
  • 优点:多个套接字的时候,可以交给select处理,比阻塞io性能高

elect :列表循环 效率低

poll :可接收得列表数据多 效率也不高

epoll :效率最高,通过异步操作 每个套接字身上绑定个回调函数,谁好了谁触发回调,(就不用去遍历了 效率低)

epoll:  windows 没有 ;linux 有

selectors: 模块 自动根据操作系统选择

import socket
import select
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)
print('settings')

rlist=[server,] #存收的套接字,有两种:conn        ,server
wlist=[] #存发的套接字
wdata={}

while True:
rl,wl,xl = select.select(rlist,wlist,[],0.5) #去向操作系统问套接字准备好没有,异常列表[] m每隔0.5秒问一次
print('rl',rl)
print('wl',wl)

for sock in rl:
if sock == server:
conn,addr = sock.accept()
rlist.append(conn)
else:
try: #适用于windows系统
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()
服务端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))

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

phone.close()
客户端

转载于:https://www.cnblogs.com/Mryang123/p/8948098.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
bailun4507 发布了0 篇原创文章 · 获赞 0 · 访问量 129 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: