并发编程:IO多路复用。
一 IO模型:
Stevens在文章中一共比较了五种IO Model:
* blocking IO#阻塞模型
* nonblocking IO#非阻塞
* IO multiplexing#多路复用
* signal driven IO#信号驱动
* asynchronous IO#异步
由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model。
再说一下IO发生时涉及的对象和步骤。对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,该操作会经历两个阶段:
#1)等待数据准备 (Waiting for the data to be ready)
#2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
记住这两点很重要,因为这些IO模型的区别就是在两个阶段上各有不同的情况。
#1、输入操作:read、readv、recv、recvfrom、recvmsg共5个函数,如果会阻塞状态,则会经理wait data和copy data两个阶段,如果设置为非阻塞则在wait 不到data时抛出异常 #2、输出操作:write、writev、send、sendto、sendmsg共5个函数,在发送缓冲区满了会阻塞在原地,如果设置为非阻塞,则会抛出异常 #3、接收外来链接:accept,与输入操作类似 #4、发起外出链接:connect,与输出操作类似
二 下面我们来首先讲blocking IO:在这种情况下没办法实现并发,因为遇到IO就阻塞。直到IO阻塞结束才会继续执行。
由上图我们可以看出,对于blocking IO模型。在传输数据的过程中,首先向操作系统发请求,经过等待数据,和copy数据的过程。
recv:经过本地copy data和wait data。
而send:只有copy data。
其实copy的过程就是从应用程序到操作系统的过程。
所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。
实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。
一个简单的解决方案:
#在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。
该方案的问题是:
#开启多进程或都线程的方式,在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,
而且线程与进程本身也更容易进入假死状态。
改进方案:
#很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。
“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,
如websphere、tomcat和各种数据库等。
改进后方案其实也存在着问题:
#“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,
“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。
对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。
三 多路复用IO(IO multiplexing)
IO multiplexing这个词可能有点陌生,但是如果我说select/epoll,大概就都能明白了。有些地方也称这种IO方式为事件驱动IO(event driven IO)。我们都知道,select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用(select和recvfrom),而blocking IO只调用了一个系统调用(recvfrom)。但是,用select的优势在于它可以同时处理多个connection。
强调:
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模型比较分析
到目前为止,已经将四个IO Model都介绍完了。现在回过头来回答最初的那几个问题:blocking和non-blocking的区别在哪,synchronous IO和asynchronous IO的区别在哪。
先回答最简单的这个:blocking vs non-blocking。前面的介绍中其实已经很明确的说明了这两者的区别。调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回。
再说明synchronous IO和asynchronous IO的区别之前,需要先给出两者的定义。Stevens给出的定义(其实是POSIX的定义)是这样子的:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operationcompletes;
An asynchronous I/O operation does not cause the requesting process to be blocked;
两者的区别就在于synchronous IO做”IO operation”的时候会将process阻塞。按照这个定义,四个IO模型可以分为两大类,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO这一类,而 asynchronous I/O后一类 。
有人可能会说,non-blocking IO并没有被block啊。这里有个非常“狡猾”的地方,定义中所指的”IO operation”是指真实的IO操作,就是例子中的recvfrom这个system call。non-blocking IO在执行recvfrom这个system call的时候,如果kernel的数据没有准备好,这时候不会block进程。但是,当kernel中数据准备好的时候,recvfrom会将数据从kernel拷贝到用户内存中,这个时候进程是被block了,在这段时间内,进程是被block的。而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。
各个IO Model的比较如图所示:
经过上面的介绍,会发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。
并发编程:IO多路复用。的更多相关文章
- 并发编程(IO多路复用)
阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asynchro ...
- 4.6 并发编程/IO模型
并发编程/IO模型 背景概念 IO模型概念 IO模型分类 阻塞IO (blocking IO) 特点: 两个阶段(等待数据和拷贝数据两个阶段)都被block 设置 server.setsockopt ...
- python 网络编程 IO多路复用之epoll
python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解 此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...
- python 并发编程 io模型 目录
python 并发编程 IO模型介绍 python 并发编程 socket 服务端 客户端 阻塞io行为 python 并发编程 阻塞IO模型 python 并发编程 非阻塞IO模型 python 并 ...
- 并发编程 - IO模型 - 1.io模型/2.阻塞io/3.非阻塞io/4.多路复用io
1.io模型提交任务得方式: 同步:提交完任务,等结果,执行下一个任务 异步:提交完,接着执行,异步 + 回调 异步不等结果,提交完任务,任务执行完后,会自动触发回调函数同步不等于阻塞: 阻塞:遇到i ...
- Python Web学习笔记之并发编程IO模型
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...
- Python之并发编程-IO模型
目录 一.IO模型介绍二.阻塞IO(blocking IO)三.非阻塞IO(non-blocking IO)四.多路复用IO(IO multiplexing)五.异步IO(Asynchronous I ...
- 并发编程 - io模型 - 总结
1.提交任务得方式: 同步:提交完任务,等结果,执行下一个任务 异步:提交完,接着执行,异步 + 回调 异步不等结果,提交完任务,任务执行完后,会自动触发回调函数2.同步不等于阻塞: 阻塞:遇到io, ...
- python网络编程——IO多路复用之select
1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...
- python并发编程&IO模型
一 IO模型介绍 为了更好地了解IO模型,可先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(n ...
随机推荐
- MySQL5.6新特性之Multi-Range Read
一 介绍 MySQL 5.6版本提供了很多性能优化的特性,其中之一就是 Multi-Range Read 多范围读(MRR) , 它的作用针对基于辅助/第二索引的查询,减少随机IO,并且将随机I ...
- webpack 4 学习资料
webpack 4 学习资料 资料 网址 webpack 中文版 https://webpack.docschina.org/configuration/ webpack 4 教程 https://s ...
- 1、Nginx集群tomcat
一.准备工作 下载nginx,http://nginx.org/,本文采用nginx-1.8.0,下载之后直接解压,免安装 下载tomcat,以配置3台tomcat服务器做负载均衡为例 二.修改tom ...
- java 加载数据库驱动
JDBC编程步骤见 JDBC编程步骤 JDBC编程的第一步是加载数据库驱动,使用Class类的forName()方法,Class.forName("com.mysql.jdbc.Driver ...
- SDI初识
SDI初识 SDI接口,即“数字分量串行接口(Serial Digital Interface)”.按照速率可以分为: 标准清晰度SD-SDI,速率为270Mb/s; 高清标准HD-SDI,速率为1. ...
- 在MacOSX系统上的一些工具和问题汇总
Android 模拟器 1. 安装模拟器 点击链接:https://cloud.genymotion.com/page/launchpad/download 需要先注册登录一下. 2.安装Virtua ...
- Ubuntu 14.10 下Hadoop FTP文件上传配置
最近老板提出一个需求,要用Hadoop机群管理生物数据,并且生物数据很多动辄几十G,几百G,所以需要将这些数据传到HDFS中,在此之前搭建了HUE用来图形化截面管理HDFS数据,但是有个问题,上面使用 ...
- springboot(二 如何访问静态资源和使用模板引擎,以及 全局异常捕获)
在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static / ...
- Linux下使用curl查看http请求各阶段耗时
1. 准备文件模版(curl.txt) \n time_namelookup: %{time_namelookup}\n time_connect: %{time_connect}\n time_ap ...
- python常用模块: random模块, time模块, sys模块, os模块, 序列化模块
一. random模块 import random # 任意小数 print(random.random()) # 0到1的任意小数 print(random.uniform(-10, 10)) # ...