python 并发编程 多路复用IO模型详解

多路复用IO(IO multiplexing)

这种IO方式为事件驱动IO(event driven IO)。

我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

select是多路复用的一种

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,
当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用\(select和recvfrom\),
而blocking IO只调用了一个系统调用\(recvfrom\)。但是,用select的优势在于它可以同时处理多个connection。

多路复用IO比较阻塞IO模型:

1.阻塞IO经历两个阶段 wait data,copy data

2.多路复用3个阶段 wait data,ready copy data, copy data

单连接套接字通信 阻塞IO效率高

多路复用IO select可以代理多个套接字连接,多个套接字通信,多路复用IO效率高

强调:

1. 如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。

2. 在多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。

结论: select的优势在于可以处理多个连接,性能高,同时可以检测多个套接字IO行为,不适用于单个连接

select网络IO模型示例

select 检测多个套接字IO行为 accept,recv

IO行为两种:

1.别人给我传数据

2.给别人发送数据

timeout是超时时间

每隔0.5秒去问操作系统准备好数据没有

def select(rlist, wlist, xlist, timeout=None):
  pass
# [] 传的空列表是出异常的列表
# 返回值3个列表 收列表,发列表,异常列表
rl,wl,xl = select.select(rlist, wlist, [], 0.5)

客户端:

from socket import *
client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8000))
while True:
  msg = input(">>>:").strip()
  if not msg:continue
  client.send(msg.encode("utf-8"))
  data = client.recv(1024)
  print(data.decode("utf-8"))
client.close()

服务端代码:

from socket import *
import select
server = socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8000))
server.listen(5)
# 设置socket接口为 非阻塞IO接口
# 默认是True 为阻塞
server.setblocking(False)
# 专门存着收消息套接字
rlist = [server,]
# 存放发送消息套接字
wlist = []
# 存放发送的数据
wdata = {}
while True:
  # 返回值3个列表 收列表,发列表,异常列表
  rl,wl,xl = select.select(rlist, wlist, [], 0.5)
  print("rl",rl)
  print("wl",wl)
  for sock in rl:
    if sock == server:
      conn,addr = sock.accept()
      rlist.append(conn)
    else:
      try:
        data = sock.recv(1024)
        if not data:
          sock.close()
          rlist.remove(sock)
          continue
        # 收的套接字加到列表
        wlist.append(sock)
        # 把数据加到字典 做一个 套接字对应数据
        wdata[sock] = data.upper()

      except Exception:
        sock.close()
        rlist.remove(sock)
  # 发送数据
  for sock in wl:
    sock.send(wdata[sock])
    wlist.remove(sock)
    wdata.pop(sock)
server.close()

基于select模块 检测套接字IO行为,实现并发效果

select监听fd变化的过程分析:

用户进程创建socket对象,拷贝监听的fd到内核空间,每一个fd会对应一张系统文件表,内核空间的fd响应到数据后,
就会发送信号给用户进程数据已到;

用户进程再发送系统调用,比如(accept)将内核空间的数据copy到用户空间,同时作为接受数据端内核空间的数据清除,
这样重新监听时fd再有新的数据又可以响应到了(发送端因为基于TCP协议所以需要收到应答后才会清除)。

该模型的优点:

可以同时检测多个套接字,效率比阻塞IO,非阻塞IO高了

相比其他模型,使用select() 的事件驱动模型只用单线程(进程)执行,占用资源少,不消耗太多 CPU,同时能够为多客户端提供服务。

如果试图建立一个简单的事件驱动的服务器程序,这个模型有一定的参考价值。

该模型的缺点:

代理的套接字 列表里的多个套接字,需要循环列表 一个个检测,

在代理套接字比较少的情况下,循环比较快。但select代理的套接字非常多的情况下,select随着列表增大,效率就越来越慢

首先select()接口并不是实现“事件驱动”的最好选择。因为当需要探测的句柄值较大时,select()接口本身需要消耗大量时间去轮询各个句柄。

很多操作系统提供了更为高效的接口,如linux提供了epoll,BSD提供了kqueue,Solaris提供了/dev/poll,…。
如果需要实现更高效的服务器程序,类似epoll这样的接口更被推荐。遗憾的是不同的操作系统特供的epoll接口有很大差异,
所以使用类似于epoll的接口实现具有较好跨平台能力的服务器会比较困难。
其次,该模型将事件探测和事件响应夹杂在一起,一旦事件响应的执行体庞大,则对整个模型是灾难性的。

epoll是异步方式实现,提交套接字时候,每个套接字身上都绑定一个回调函数,哪个套接字准备好了,就触发回调函数,把自己索引放在单独列表里,对于select来说,只需要去准备好的列表里 根据索引拿到套接字,这样不需要在列表里每个遍历。

epoll不支持windows系统

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Python音频操作工具PyAudio上手教程详解

    ​ 0.引子 当需要使用Python处理音频数据时,使用python读取与播放声音必不可少,下面介绍一个好用的处理音频PyAudio工具包. PyAudio是Python开源工具包,由名思义,是提供对语音操作的工具包.提供录音播放处理等功能,可以视作语音领域的OpenCv. 1.简介 PyAudio为跨平台音频I / O库 PortAudio 提供 Python 绑定.使用PyAudio,您可以轻松地使用Python在各种平台上播放和录制音频,例如GNU / Linux,Microsoft Wi

  • python并发2之使用asyncio处理并发

    asyncio 在Python 2的时代,高性能的网络编程主要是使用Twisted.Tornado和Gevent这三个库,但是它们的异步代码相互之间既不兼容也不能移植.如上一节说的,Gvanrossum希望在Python 3 实现一个原生的基于生成器的协程库,其中直接内置了对异步IO的支持,这就是asyncio,它在Python 3.4被引入到标准库. asyncio 这个包使用事件循环驱动的协程实现并发. asyncio 包在引入标准库之前代号 "Tulip"(郁金香),所以在网上搜

  • Python中的并发处理之asyncio包使用的详解

    导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流. 本文重点: 1.了解asyncio包的功能和使用方法: 2.了解如何避免阻塞型调用: 3.学会使用协程避免回调地狱. 一.使用asyncio包做并发编程 1.并发与并行 并发:一次处理多件事. 并行:一次做多件事. 并发用于制定方案,用来解决可能(但未必)并行的问题.并发更好. 2.asyncio概述 了解asyncio的4个特点: asyncio包使用事件循环驱动的

  • 详解python异步编程之asyncio(百万并发)

    前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥补了python性能方面的短板,如最新的微服务框架japronto,resquests per second可达百万级. python还有一个优势是库(第三方库)极为丰富,运用十分方便.asyncio是python3.4版本引入到标准库,python2x没有加这个库,毕竟python3x才是未来啊,哈哈!python3.5又加入了asyn

  • Python使用asyncio包处理并发详解

    阻塞型I/O和GIL CPython 解释器本身就不是线程安全的,因此有全局解释器锁(GIL),一次只允许使用一个线程执行 Python 字节码.因此,一个 Python 进程通常不能同时使用多个 CPU 核心. 然而,标准库中所有执行阻塞型 I/O 操作的函数,在等待操作系统返回结果时都会释放GIL.这意味着在 Python 语言这个层次上可以使用多线程,而 I/O 密集型 Python 程序能从中受益:一个 Python 线程等待网络响应时,阻塞型 I/O 函数会释放 GIL,再运行一个线程

  • python 缺失值处理的方法(Imputation)

    一.缺失值的处理方法 由于各种各样的原因,真实世界中的许多数据集都包含缺失数据,这些数据经常被编码成空格.nans或者是其他的占位符.但是这样的数据集并不能被scikit - learn算法兼容,因为大多数的学习算法都会默认数组中的元素都是数值,因此素偶有的元素都有自己的代表意义. 使用不完整的数据集的一个基本策略就是舍弃掉整行或者整列包含缺失值的数值,但是这样处理会浪费大量有价值的数据.下面是处理缺失值的常用方法: 1.忽略元组 当缺少类别标签时通常这样做(假定挖掘任务涉及分类时),除非元组有

  • Python多进程并发(multiprocessing)用法实例详解

    本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心. Python提供了非常好用的多进程包multiprocessing,你只需要定义一个函数,Python会替你完成其他所有事情.借助这个包,可以轻松完成从单进程到并发执行的转换. 1.新建单一进程 如果我们新建少量进程,可以如下: import multiprocessing import t

  • python 并发编程 多路复用IO模型详解

    多路复用IO(IO multiplexing) 这种IO方式为事件驱动IO(event driven IO). 我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个网络连接的IO.它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程.它的流程如图: select是多路复用的一种 当用户进程调用了select,那么整个进程会被block,而同时,kernel会"监视&qu

  • python 并发编程 阻塞IO模型原理解析

    阻塞IO(blocking IO) 在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样: 当用户进程调用了recvfrom这个系统调用,kernel内核就开始了IO的第一个阶段:准备数据.对于network io( 网络io )来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel( 内核 )就要等待足够的数据到来. 等着对方把数据放到自己操作系统内存 而在用户进程这边,整个进程会被阻塞.当kernel一直等

  • Java 中的io模型详解

    1. BIO 我们先看一个 Java 例子: package cn.bridgeli.demo;   import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;   /**  * @author bridgel

  • Python并发编程之IO模型

    五种IO模型 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO 异步(asynchronous) IO 阻塞(blocking) IO 非阻塞(non-blocking)IO 五种I/O模型包括:阻塞I/O.非阻塞I/O.信号驱动I/O(不常用).I/O多路转接.异步I/O.其中,前四个被称为同步I/O. 上五个模型的阻塞程度由低到高为:阻塞I/O > 非阻塞I/O > 多路转接I/O > 信号驱动I/O > 异步I/O,因

  • Java并发编程Semaphore计数信号量详解

    Semaphore 是一个计数信号量,它的本质是一个共享锁.信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量). 简单示例: package me.socketthread; import java.util.concurrent.ExecutorService;

  • Java并发编程总结——慎用CAS详解

    一.CAS和synchronized适用场景 1.对于资源竞争较少的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源:而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能. 2.对于资源竞争严重的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized.以java.util.concurrent.atomic包中AtomicInteger类为例,其getAn

  • Python中函数参数匹配模型详解

    当我们的函数接收参数为任意个,或者不能确定参数个数时,我们,可以利用 * 来定义任意数目的参数,这个函数调用时,其所有不匹配的位置参数会被赋值为元组,我们可以在函数利用循环或索引进行使用 def f(*args): # 直接打印元组参数 print(args) print('-'*20) # 循环打印元组参数 [print(i) for i in args] ... # 传递一个参数 f(1) print('='*20) # 传递5个参数 f(1, 2, 3, 4, 5) 示例结果: (1,)

  • Java并发编程预防死锁过程详解

    这篇文章主要介绍了Java并发编程预防死锁过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在java并发编程领域已经有技术大咖总结出了发生死锁的条件,只有四个条件都发生时才会出现死锁: 1.互斥,共享资源X和Y只能被一个线程占用 2.占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X 3.不可抢占,其他线程不能强行抢占线程T1占有的资源 4.循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有

  • Python面向对象编程repr方法示例详解

    目录 为什么要讲 __repr__ 重写 __repr__ 方法 str() 和 repr() 的区别 为什么要讲 __repr__ 在 Python 中,直接 print 一个实例对象,默认是输出这个对象由哪个类创建的对象,以及在内存中的地址(十六进制表示) 假设在开发调试过程中,希望使用 print 实例对象时,输出自定义内容,就可以用 __repr__ 方法了 或者通过 repr() 调用对象也会返回 __repr__ 方法返回的值 是不是似曾相识....没错..和 __str__ 一样的

  • Go语言并发编程基础上下文概念详解

    目录 前言 1 Go 中的 Context 2 Context 接口 3 Context Tree 4 创建上下文 4.1 上下文创建函数 4.2 Context 使用规范 4.3 Context 使用场景 5 总结 前言 相信大家以前在做阅读理解的时候,一定有从老师那里学一个技巧或者从参考答案看个:结合上下文.根据上下文我们能够找到有助于解题的相关信息,也能更加了解段落的思想. 在开发过程中,也有这个上下文(Context)的概念,而且上下文也必不可少,缺少上下文,就不能获取完整的程序信息.那

随机推荐