码迷,mamicode.com
首页 > 编程语言 > 详细

python IO模型

时间:2018-05-29 01:39:02      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:server   系统   添加   报错   output   NPU   监听   异步io   直接   

详细带图

第一种IO模型
阻塞

 

第二种IO模型
非阻塞IO
原理:由阻塞改为非阻塞,每隔一段时间回来看看(每每看一次,内核态会发送一次系统调用),若没有干其他事情(适用于代码量小),进程主动轮询
当服务器端套接字被setblocking(false),套接字为非阻塞套接字,当接收不到客户端链接时,直接触发异常(证明现阶段CPU空闲,可以做其他事情)。所以可以在异常处理处理其他任务。

 

缺点
发送太多次系统调用
数据得不到及时处理

 

第三种IO模型
IO多路复用(单线程下实现并发,原理就是利用IO空闲时间实现并发)(select ,poll,epoll)
select
select函数是系统调用接口。并且select也是会阻塞,
但其好处是同时可监控多个链接,这是决定了为何如此流行.
讲到这里还是莫名其妙,但是可以把socket.accpet()返回的conn添加至监听列表里,就明白了。因为监听那么多,总有一个是内核态有数据的,也就是说总会可以操作的
注意的是:默认,若内核态的数据没有取至用户态,则返回的可读列表里会一直存在该套接字。还有监听数不能超过1024

# select 模拟一个socket server,注意socket必须在非阻塞情况下才能实现IO多路复用。
# 接下来通过例子了解select 是如何通过单进程实现同时处理多个非阻塞的socket连接的。
#server端


import select
import socket
import queue

server = socket.socket()
server.bind((localhost,9000))
server.listen(1000)

server.setblocking(False)  # 设置成非阻塞模式,accept和recv都非阻塞
# 这里如果直接 server.accept() ,如果没有连接会报错,所以有数据才调他们
# BlockIOError:[WinError 10035] 无法立即完成一个非阻塞性套接字操作。
msg_dic = {}
inputs = [server,]  # 交给内核、select检测的列表。
# 必须有一个值,让select检测,否则报错提供无效参数。
# 没有其他连接之前,自己就是个socket,自己就是个连接,检测自己。活动了说明有链接
outputs = []  # 你往里面放什么,下一次就出来了

while True:
    readable, writeable, exceptional = select.select(inputs, outputs, inputs)  # 定义检测
    #新来连接                                        检测列表         异常(断开)
    # 异常的也是inputs是: 检测那些连接的存在异常
    print(readable,writeable,exceptional)
    for r in readable:
        if r is server:  # 有数据,代表来了一个新连接
            conn, addr = server.accept()
            print("来了个新连接",addr)
            inputs.append(conn)  # 把连接加到检测列表里,如果这个连接活动了,就说明数据来了
            # inputs = [server.conn] # 【conn】只返回活动的连接,但怎么确定是谁活动了
            # 如果server活动,则来了新连接,conn活动则来数据
            msg_dic[conn] = queue.Queue()  # 初始化一个队列,后面存要返回给这个客户端的数据
        else:
            try :
                data = r.recv(1024)  # 注意这里是r,而不是conn,多个连接的情况
                print("收到数据",data)
                # r.send(data) # 不能直接发,如果客户端不收,数据就没了
                msg_dic[r].put(data)  # 往里面放数据
                outputs.append(r)  # 放入返回的连接队列里
            except ConnectionResetError as e:
                print("客户端断开了",r)
                if r in outputs:
                    outputs.remove(r) #清理已断开的连接
                inputs.remove(r) #清理已断开的连接
                del msg_dic[r] ##清理已断开的连接

    for w in writeable:  # 要返回给客户端的连接列表
        data_to_client = msg_dic[w].get()  # 在字典里取数据
        w.send(data_to_client)  # 返回给客户端
        outputs.remove(w)  # 删除这个数据,确保下次循环的时候不返回这个已经处理完的连接了。

    for e in exceptional:  # 如果连接断开,删除连接相关数据
        if e in outputs:
            outputs.remove(e)
        inputs.remove(e)
        del msg_dic[e]


#*************************client
import socket
client = socket.socket()

client.connect((localhost, 9000))

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

client.close()

 

poll
相比select,就是一点,就是把最大链接数提高了

 

epoll
epoll实现原理跟select一样(原理图一样),但是实现机制不同(也就是,数据来了,是怎么找到是指定套接字的)

 

select内部原理是采取轮询,就好比,在一间教室里老师听到有一学生拍了下桌子,但不知道具体谁拍的,
只有一个一个问。所以很多时间都消耗在轮询问上面了(是每一次有数据到来时候,都要轮询)
epoll内部原理是自报家门,就好比,学生不拍桌子,直接站起来我是谁,我要反了
Ngexi服务器底层就是epoll,多进程多线程开得不多,但是一个线程里面通过epoll实现多连接

 


异步IO

异步是整个过程中一点阻塞都没有。你发完请求你就去做其他事情,等到内核把数据收到且复制到用户态,再发给你一个信号。
所以说以上IO多路复用,不是异步的。

同步IO
在IO操作完成之前存在阻塞。而异步IO是毫无阻塞。所以多路复用都属于同步IO

 

python IO模型

标签:server   系统   添加   报错   output   NPU   监听   异步io   直接   

原文地址:https://www.cnblogs.com/ziyide/p/9103062.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!