首页 > 其他 > 详细

035_IO 模型

时间:2019-04-18 22:51:11      阅读:179      评论:0      收藏:0      [点我收藏+]

IO 模型分类

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

1,阻塞IO 的图

  recv数据

技术分享图片

  阻塞IO

技术分享图片

  非阻塞IO

技术分享图片

 

  IO多路复用

技术分享图片

2,

  阻塞IO    : 工作效率低
  非阻塞IO  : 工作效率高,频繁询问切换加大CPU的负担
  IO多路复用: 在有多个对象需要IO阻塞的时候,能够有效的减少阻塞带来的时间损耗,且能够在一定程度上减少CPU的负担
  异步IO : asyncio  异步IO  工作效率高 CPU的负担少

3,网络IO

       # recv     recvfrom   accept   requests.get()
       # send    connect    sendto
4,IO的两个阶 段
       # 数据准备阶段
       # 数据copy阶段
 
解决阻塞IO 问题
   1)多进程 多线程 分离了阻塞
    但进程线程不能无限开!
   2)以后用进程都用进程池
    单纯的进程池不能满足用户的需求,只适合小并发的问题,真正需要我们解决的是I/O问题
1,非阻塞IO实例
技术分享图片
import socket
sk = socket.socket()
sk.bind((127.0.0.1,8080))
sk.listen()
sk.setblocking(False)    
 # 异步的,但是来不及打开client端建立连接,就已经报错
# 因为下一句不阻塞了
# recv 也不阻塞了,但一样会报错 ,有连接时,且设为不阻塞时,没消息就打印空消息。
# 原因:调用阻塞异常错误(变量没有被赋值)
conn,addr = sk.accept()
print(conn)
sever端
技术分享图片
import socket
sk = socket.socket()
sk.bind((127.0.0.1,8080))
sk.listen()
sk.setblocking(False)
conn_lst = []    # 用来保存已经建立的连接

while True:
    try:
        conn,addr = sk.accept()   #非阻塞  
        conn_lst.append(conn)   # 不将建立成功的连接用列表保存下来,conn会不断被新连接覆盖。
    except BlockingIOError:
        del_lst = []
        for c in conn_lst:    
            try:
                msg = c.recv(10).decode(utf-8)  # recv不会阻塞
                if not msg:
                    c.close()
                    del_lst.append(c)
                else:
                    print(msg)
                    c.send(msg.upper().encode(utf-8))
            except BlockingIOError:
                pass
        if del_lst:
            for del_item in del_lst:
                conn_lst.remove(del_item)
sever端改进
技术分享图片
import time
import socket
import threading
def func():
    sk = socket.socket()
    sk.connect((127.0.0.1,8080))
    time.sleep(1)
    sk.send(bhi)
    print(sk.recv(10))
    sk.close()

for i in range(10):
    threading.Thread(target=func,).start()
client端

多路复用

# 操作系统提供的多路复用机制
      #  select  、 poll 、  epoll、
      # windows 上只有 select
      # linux 兼容三种

  # 原来是recv,现在是交给select ;select([recv])

技术分享图片

1,参数

  select(rlist,wlisr,xlist,timeout = None)
            等能  读,写,改   三个参数是列表,必须传参,没有参数传空列表。返回的结果是一个有三个列表的元组,分别是读,写,改的结果。

2,实例

技术分享图片
import time
import socket
import threading
def client_async(args):
    sk = socket.socket()
    sk.connect((127.0.0.1,8099))
    for i in range(10):
        time.sleep(2)
        sk.send((%s[%s] :hello%(args,i)).encode(utf-8))
        print(sk.recv(1024))
    sk.close()

for i in range(10):
    threading.Thread(target=client_async,args=(**i,)).start()
client端
技术分享图片
import socket
import select
sk = socket.socket()
sk.bind((127.0.0.1,8099))
sk.listen()

read_lst = [sk]
while True:
    rl,wl,xl = select.select(read_lst,[],[])   # select阻塞,rl可以读的 wl可以写的 xl可以改的  [sk,conn]
    for item in rl:
        if item == sk:
            conn,addr = item.accept()  # 有数据等待着它接收
            read_lst.append(conn)
        else:
            ret = item.recv(1024).decode(utf-8)
            if not ret:
                item.close()
                read_lst.remove(item)
            else:
                print(ret)
                item.send((received %s%ret).encode(utf-8))
sever 端

3,

# select poll 随着要检测的数据增加 效率会下降,不适合处理大并发。
# select  有数目的限制
# poll    能处理的对象更多
# epoll   能处理多对象且 不是使用轮询  而是用回调函数 —— linux
#这三种IO多路复用模型在不同的平台有着不同的支持,而epoll在windows下就不支持,好在我们有selectors模块,帮我们默认选择当前平台下最合适的
技术分享图片
from socket import *
import selectors

sel=selectors.DefaultSelector()   # 创建一个默认的多路复用模型
def accept(sk):
    conn,addr=sk.accept()
    sel.register(conn,selectors.EVENT_READ,read)

def read(conn):
    try:
        data=conn.recv(1024)
        if not data:   #win8 win10
            print(closing,conn)
            sel.unregister(conn)
            conn.close()
            return
        conn.send(data.upper()+b_SB)
    except Exception:    # linux操作系统
        print(closing, conn)
        sel.unregister(conn)
        conn.close()

sk=socket(AF_INET,SOCK_STREAM)
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
sk.bind((127.0.0.1,8088))
sk.listen(5)
sk.setblocking(False) #设置socket的接口为非阻塞
sel.register(sk,selectors.EVENT_READ,accept) #相当于网select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept

while True:
    events=sel.select() #检测所有的fileobj,是否有完成wait data的   #[sk,conn]
    for sel_obj,mask in events:   # 有人触动了你在sel当中注册的对象
        callback=sel_obj.data #callback=accpet   # sel_obj.data就能拿到当初注册的时候写的accept/read方法
        callback(sel_obj.fileobj) #accpet(sk)/read(conn)
服务端

 

035_IO 模型

原文:https://www.cnblogs.com/eternity-twinkle/p/10732921.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!