ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并发05--网络IO模型

2022-07-13 08:32:26  阅读:158  来源: 互联网

标签:socket 05 -- list server IO data conn


IO模型简介

# 我们这里研究的IO模型都是针对网络IO

Stevens在文章中一共比较了五种IO Model:
  * blocking IO           阻塞IO
  * nonblocking IO        非阻塞IO
  * IO multiplexing       IO多路复用
  * asynchronous IO       异步IO
  * signal driven IO      信号驱动IO
  # 由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model

# 1.等待数据准备 (Waiting for the data to be ready)
# 2.将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

同步异步
阻塞非阻塞

# 常见的网络阻塞状态:
    accept  # tcp的等待链接
    recv    # tcp的接受数据
    recvfrom  # udp的接受数据 
    
    send # 虽然它也有io行为 但是不在我们的考虑范围(是主动的操作,且IO时间短)

简单的网络数据传输过程-图解

recv的过程(被动的等待):

1.阻塞IO模型

官方图解

# 阻塞IO模型
  程序在接受到数据之前,都处于阻塞状态,只有接受到数据后,才会往下执行
  # 我们之前写的都是阻塞IO模型  协程除外

import socket


# 服务端
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)


while True:
    conn, addr = server.accept()
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:break
            print(data)
            conn.send(data.upper())
        except ConnectionResetError as e:
            break
    conn.close()
 
# 客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

    
# 在服务端开设多进程或者多线程 进程池线程池 其实还是没有解决网络IO问题	
  该等的地方还是得等 没有规避
  每个人都会在该等的地方,还是会等待,只不过多个人等待的彼此互不干扰

2.非阻塞IO

官方图解

这样做的好处:程序不会因IO操作进入阻塞态,虽然返回结果的数据依旧没有拿到,但可以一直占着CPU,切换进行其他的操作。

# 非阻塞IO模型
  程序在系统调用时(跟操作系统内核要数据),无论是否获取到数据,都立刻返回一个结果
  程序会根据结果(是否获取到数据),进行不同的操作(继续调用或向下执行),不会一直处于阻塞状态
  

# eg: 要自己实现一个非阻塞IO模型
import socket
import time


server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)

# 将所有的网络阻塞变为非阻塞
server.setblocking(False)

r_list = []
del_list = []  # 临时将需要无用的连接删除
while True:
    try:
        conn, addr = server.accept()
        r_list.append(conn)
        
    # 这里并不是真的出错,而是阻塞变成非阻塞后,系统调用后,没有数据时的反馈(BWOULDBLOCK)
    except BlockingIOError:
        # time.sleep(0.1)
        # print('列表的长度:',len(r_list))
        # print('做其他事')
        for conn in r_list:
            try:
                data = conn.recv(1024)  # 没有消息 报错
                if len(data) == 0:  # 客户端断开链接
                    conn.close()  # 关闭conn
                    # 将无用的conn从r_list删除
                    del_list.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                continue
            except ConnectionResetError:
                conn.close()
                del_list.append(conn)
        # 回收无用的链接
        for conn in del_list:
            r_list.remove(conn)
        del_list.clear()

# 客户端
import socket


client = socket.socket()
client.connect(('127.0.0.1',8081))


while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

总结

虽然非阻塞IO给你的感觉非常的牛逼
但是该模型会	长时间占用着CPU并且不干活 让CPU不停的空转
我们实际应用中也不会考虑使用非阻塞IO模型

任何的技术点都有它存在的意义 
实际应用或者是思想借鉴

3.IO多路复用***

官方图解

# IO多路复用模型
  操作系统内部提供一个监管机制,能够帮程序监管socket和conn对象,
  并且可以监管多个,只有系统数据获取到,就会返回对应的监管对象

  当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!
  但是IO多路复用可以一次性监管很多个对象

# 存在IO阻塞的部分是 accept 和 recv ,分别是server对象和conn对象
server = socket.socket()
conn,addr = server.accept()


# eg: 手动实现IO多路复用

监管机制(内部实现其实跟非阻塞IO一样)是操作系统本身就有的 
如果你想要用该监管机制(select) 需要你导入对应的select模块


import socket
import select


server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)
read_list = [server]


while True:
    r_list, w_list, x_list = select.select(read_list, [], [])  
    # select返回的是一个元祖,元祖中的第一个列表包含 监管到的 多个对象。
    
    """
    帮你监管,一旦有人来了 立刻给你返回对应的监管对象
    """
    # 此时,若有server连接对象,就会被select监管到 在返回的元祖第一个列表中
    # res = select.select(read_list, [], [])
    # print(res)  # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
    # print(server)  # 和select返回的结果,和server对象一样
    # print(r_list)  # 因为做了循环监管,此时就不仅仅只有server对象,还有conn对象。所以后续做了对象的判断。
    
    for i in r_list:  #
        """针对不同的对象做不同的处理"""
        if i is server: # server对象就连接操作
            conn, addr = i.accept()
            # conn 也应该添加到监管的队列中
            read_list.append(conn)
        else: # conn对象就行通信操作
            res = i.recv(1024)
            if len(res) == 0:
                i.close()  # 关闭conn连接
                # 将无效的监管对象 移除
                read_list.remove(i)
                continue
            print(res)
            i.send(b'heiheiheiheihei')

 # 客户端
import socket


client = socket.socket()
client.connect(('127.0.0.1',8080))


while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

总结

# 监管机制其实有很多
1.select机制  windows linux都有

2.poll机制    只在linux有   poll和select都可以监管多个对象 但是poll监管的数量更多

上述select和poll机制其实都不是很完美 当监管的对象特别多的时候
可能会出现 极其大的延时响应

3. epoll机制   只在linux有       # redis 就是采用 IO多路复用模型 + epoll机制
    它给每一个监管对象都绑定一个回调机制
    一旦有响应 回调机制立刻发起提醒

针对不同的操作系统还需要考虑不同检测机制 书写代码太多繁琐
有一个人能够根据你跑的平台的不同自动帮你选择对应的监管机制
selectors模块

4.异步IO

官方图解

# 异步IO模型
  程序在进行系统调用时(获取数据),是异步操作,cpu切换,进行其他操作
  根据系统调用的回调机制,再执行 接受到数据的处理

# 异步IO模型是所有模型中效率最高的 也是使用最广泛的
相关的模块和框架
  模块: asyncio模块
  异步框架:sanic tronado twisted
	   速度快!!!

        
import threading
import asyncio  # 游戏、交互式画面、爬虫 


@asyncio.coroutine
def hello():
    print('hello world %s'%threading.current_thread())
    yield from asyncio.sleep(1)  # 换成真正的IO操作
    print('hello world %s' % threading.current_thread())


loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

四个IO模型对比

官方图解

参考博客园图解,稍微了解即可
https://www.cnblogs.com/Dominic-Ji/articles/10929396.html

标签:socket,05,--,list,server,IO,data,conn
来源: https://www.cnblogs.com/Edmondhui/p/16472478.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有