精华内容
下载资源
问答
  • 阻塞IO与非阻塞IO区别
    2021-08-25 10:11:23

    阻塞IO与非阻塞IO的区别

    阻塞IO,指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户的操作。阻塞是指用户空间的执行状态。
    非阻塞IO,指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户操作,即处于非阻塞IO状态,内核空间会立即返回给用户一个状态值。

    阻塞IO:调用线程一直在等待,不能干别的事情。
    非阻塞IO:调用线程拿到内核返回的状态值后,IO操作能干就干2,不能就干别的事情。

    更多相关内容
  • 在JDK1.4中引入了一个NIO的类库,使得Java涉及IO的操作拥有阻塞式非阻塞式两种,问一下阻塞IO与非阻塞IO有什么区别?有什么优缺点?在阻塞模式 下,若从网络流中读取不到指定大小的数据量,阻塞IO就在那里阻塞着。...

    在JDK1.4中引入了一个NIO的类库,使得Java涉及IO的操作拥有阻塞式和非阻塞式两种,问一下阻塞IO与非阻塞IO有什么区别?有什么优缺点?

    在阻塞模式 下,若从网络流中读取不到指定大小的数据量,阻塞IO就在那里阻塞着。比如,已知后面会有10个字节的数据发过来,但是我现在只收到8个字节,那么当前线 程就在那傻傻地等到下一个字节的到来,对,就在那等着,啥事也不做,直到把这10个字节读取完,这才将阻塞放开通行。

    在非阻塞模式下,若从网络流中读取不到指定大小的数据量,非阻塞IO就立即通行。比如,已知后面会有10个字节的数据发过来,但是我现在只收到8个字节,那么当前线程就读取这8个字节的数据,读完后就立即返回,等另外两个字节再来的时候再去读取。

    从上面可以看 出,阻塞IO在性能方面是很低下的,如果要使用阻塞IO完成一个Web服务器的话,那么对于每一个请求都必须启用一个线程进行处理。而使用非阻塞IO的 话,一到两个线程基本上就够了,因为线程不会产生阻塞,好比一下接收A请求的数据,另一下接收B请求的数据,等等,就是不停地东奔西跑,直接到把数据接收 完了。

    虽然说,非阻塞IO比阻塞IO有更高的性能,但是对于开发来的,难度就成数倍递增了。由于是有多少数据就读取多少数据,这样在读取完整之前需要将已经读取到的数据保存起来,而且需要与其他地方来的数据隔离开来不能混在一起,否则就不知道这数据是谁的了

    展开全文
  • 不得不说,我对于nio与bio的区别了解的不够透彻,而这非常影响对于Netty的学习。这一篇博客会总结下我对nio与bio的学习与了解。(一部分 未完)为了能更深入的说明两者之间的区别,会从 socket编程 ->...

    在研究Netty源码的过程中,可能是由于对java的nio编程方式不够熟习,关于Selector以及线程那一块,看起来总是觉得差一点。于是,抽空研究了下jdk 的 nio与bio。不得不说,我对于nio与bio的区别了解的不够透彻,而这非常影响对于Netty的学习。这一篇博客会总结下我对nio与bio的学习与了解。(一部分 未完)

    为了能更深入的说明两者之间的区别,会从 socket编程 -> nio编程 开始一步步说明。

    文章比较长,假如时间紧可以看下阻塞IO的局限性这一段

    socket编程

    用户端bio编程

    9f246192da81c45d940e3e2742821550.png

    这里举的例子非常简单了,忽略了异常、超时等等各种情况。实际使用也不大可能仅仅只是读几条数据,就直接关流。这样写主要是为了简单,便于说明API。

    简单来说,可以总结这样几点:

    1)创立socket(指定要连接的ip及端口)

    2)获取并解决输入流

    3)关闭socket(真实场景这一步可能是在退出APP后)

    服务端bio编程

    7d6608cd7932b95376c5ccf2208894ab.png

    服务端也非常简单,大致就是:

    1)启动一个服务端,监听某一个端口

    2)接收用户端连接

    3)根据用户端的请求,写入响应(这里用户端请求没有数据)

    4)关闭服务器(真实场景可能在服务器中止时触发)

    阻塞IO解决多个用户端请求

    上述示例只是为了说明服务端API的使用。真实场景当然不可能只有一个用户端连接为了支持多个用户端,我们简单的加个循环。

    49d39fc2782f0f2214d3c0117ad1395e.png

    1)通过for循环,服务端就变的能解决多个用户端连接

    2)注释掉serverSocket.close();是由于上面while(true)最后一条语句怎样样都执行不到了。真实场景一定会有个触发close的地方。

    某个连接解决导致服务端无法响应

    上述写法,从逻辑上来看改成伪代码如下:

    8c1eb03c2ffe1e73cccbffcbf0bbde11.png

    这种写法有个非常严重的问题:

    因为整个接收请求和解决请求都是在同一个线程里(本示例是主线程)当解决用户端请求这一步发生了阻塞,或者者说慢了,后来的所有连接请求都会被阻塞住。

    9922c402afe7a02683fe135fbb7a2d3b.png

    处理方法也很简单,启动一个线程去专门解决每一个请求

    0ea86c6d6415dc26c98f62e2508fdacf.png

    这样解决流程就变成这样了:

    a544a2fa76fb51eb46b505908cd7fb06.png

    上述方式尽管处理了,某个用户端请求阻塞导致的服务端无法解决连接的问题。但是每次一个新的连接,都会启动一个线程。其余不说,假设有1百万个连接,按照一个连接最少64k来算,64k*1000000 约 61G

    (关于一个线程需要多少内存,可以看这个启动一个线程所需内存)按这么算,当连接足够多时,服务端啥都不用干,内存就会被撑爆。

    使用线程池解决超多连接

    处理方式也很简单,不再每次连接进来都去启动一个线程,而是改成使用线程池

    979ae316dd636d8c8fa52f623fc549c2.png

    整个流程大致如下:

    6d9d395632dc166609dc053a2cc9f287.png

    单个线程解决阻塞导致的其余连接无法响应问题

    使用线程池意味着,一个线程可能会解决来自多个用户端连接的请求,比方A用户端和B用户端恰好请求都被提交给 线程C,那么结果就是,A用户端的解决慢了,B用户端会连带着响应的特别慢。或者者A用户端的请求阻塞了,B用户端的请求也会连带着阻塞了。

    阻塞IO的局限性

    那么如何处理这个问题呢?在深入研究NIO和BIO的区别时,我第一反应就是使用非阻塞IO呀。但是,其实我没有弄清楚究竟非阻塞IO和阻塞IO的核心区别是啥。

    首先非阻塞IO和阻塞IO最重要的一点区别,我认为是,非阻塞IO的读、写、接收连接是不会产生阻塞的

    啥意思呢,首先回到之前写的服务端的示例:

    a9907aa99059b51f664470905fedcd3e.png

    当时我没有说明一个非常重要的情况,假设一直没有用户端的连接进来,这一步就会阻塞住。而这完全是没有必要的,由于可能在一段时间,根本不会有用户端去连接服务端。我们希望的情况是,用户端有连接了,我们再去accept,打个比如,我再卖菜,我当然希望有人来买菜了,我才去收银。而不是,就在收银台那边干等着,白费时间。

    再来看看上述问题——单个线程解决阻塞导致的其余连接无法响应,我们首先要问,为啥会产生阻塞?

    第一个起因,由于业务解决很慢。比方读写DB,可能业务就是要读取、写入很多数据,这种慢是没有办法的,无论怎样样,就是需要这么多时间。

    第二个起因,socket的读写慢了。由于阻塞IO的读与写都是阻塞的。也就是说,假设服务端开始读了,服务端在用户端发送数据之前会一直阻塞住 啥问题呢,如下图:

    902e7d53ab85d7dab32a8a10e41af69f.png

    假设用户端A和用户端B都是在一个线程中解决,用户端A已经开始读了(调用了 InputStream.read方法),但是因为没数据,服务端只能阻塞住。用户端B呢,尽管它有数据准备发给服务端,但是由于该线程已经被阻塞住了,所以用户端B的连接也只能等着。

    写的场景也一样,假设服务端准备往A写数据,但是呢数据还没准备好,导致用户端B也只能在那等着。(真实场景,这种情况可能比较少。比方收到一个查询db的请求,我们都是从db里读取了数据之后,才会调用write方法写数据的。很少会出现没有数据的问题)

    那么比较理想的情况是啥呢?只有用户端有数据发过来了,服务端才去读,才去解决这也就是非阻塞IO。

    到了这里,阻塞IO与非阻塞IO一个非常重要的区别应该就清楚了,阻塞IO的读、写、连接都会阻塞整个线程

    非阻塞IO的写法public static void main(String[] args) throws Exception { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8888)); serverSocketChannel.configureBlocking(false); //设置服务端操作都是非阻塞的 Selector selector = Selector.open(); //选择器 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //对用户端的accept事件关心 while (true) { selector.select(); //会阻塞住,直到有事件触发 Set selectionKeys = selector.selectedKeys(); //看下有哪些事件被触发了 System.out.println("selectionKeys:" + selectionKeys); Iterator iterator = selectionKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if (key.isAcceptable()) { //用户端 accept被触发了 ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel(); SocketChannel clientChannel = serverChannel.accept(); System.out.println("channel is acceptable"); clientChannel.configureBlocking(false); //用户端channel注册OP_WRITE事件 clientChannel.register(selector, SelectionKey.OP_WRITE); } else if (key.isWritable()) { //用户端可以往里写数据了 System.out.println("channel is writeable"); String data = "hello world\n"; //注意这里的是用户端的channel,由于是使用用户端channel注册OP_WRITE事件 SocketChannel clientChannel = (SocketChannel)key.channel(); ByteBuffer buffer = ByteBuffer.allocate(data.length()); buffer.put(data.getBytes()); buffer.flip(); clientChannel.write(buffer); } key.cancel(); //取消事件 iterator.remove(); } }}

    由于这里只是为了说明java nio的写法,所以写的不是很严谨。仅供参考。。实际使用别这么写。

    第一次看nio写法时候,很乱,不能了解为啥阻塞IO写起来那么清楚,到了非阻塞IO就变得这么复杂了呢?这里的Selector究竟是啥?这里的SelectionKey又是啥?为啥要判断 acceptable为啥?为啥又要判断writable?

    首先牢记一点非阻塞IO的所有操作都是异步的,这意味着什么?首先当我们直接调用 serverSocketChannel.accept(); 很可能直接返回一个null,由于用户端没有连接进来。而阻塞IO会一直等到用户端有连接

    在拿服务端读作为例子,当我们直接调用SocketChannel.read()时,可能获取到的就直接是null,而阻塞IO会一直阻塞,直到用户端向服务端发送了数据

    这样来看,由于所有请求都是异步,服务端必需要有某种机制,能知道:

    1)用户端的连接过来了

    2)用户端发送数据过来了

    3)用户端可写了

    ....

    而得知这些的方式,就是Selector。通过Selector的select操作,我们能遍历出当前有哪些事件准备好了,比方用户端连接过来了、用户端有数据过来了、可以往用户端发送数据了。

    到目前为止,应该能说明为啥非阻塞IO的API设计是这样。更详细的java nio的使用,会在后面的博客里说明。

    一个小问题:非阻塞IO是不是肯定比阻塞IO性能要好?

    分析到这里,可能会有种感觉,非阻塞IO性能肯定比阻塞IO性能要好。但是其实这样说,并不精确。非阻塞IO处理了服务端有很多不活跃连接 的问题,比方说,用户端连接后,很长一段时间不发送任何请求,这样服务端解决该连接的线程就会一直卡在那里。

    但是当连接不多时,并且每个连接都很活跃时,阻塞IO性能可能比非阻塞要好。

    总结

    这篇博客说明了java 阻塞IO与非阻塞IO的一个非常重要的区别——IO操作能否阻塞。非阻塞IO处理了大量不活跃连接的问题。

    问题

    非阻塞IO与阻塞IO的区别当然不止这些,对于非阻塞IO的API说明也没有非常详尽。比方非阻塞IO里的buffer是啥?为啥非阻塞IO使用起来,要比阻塞IO复杂的多?后面博客会详细说明这几点。

    展开全文
  • 网络IO模型:同步IO异步IO,阻塞IO和非阻塞IO
  • 本文主要讲了IO中同步、异步与阻塞、非阻塞区别。希望对你的学习有所帮助。
  • 首先我们来定义流的概念,不管是文件,...根据不同的处理办法,可以把IO分为阻塞或者非阻塞的: 阻塞:阻塞是个什么概念呢?比如某个时候你在等快递,但是你不知道快递什么时候过来,而且你没有别的事可以干(或者

    首先我们来定义流的概念,不管是文件,还是套接字,还是管道,我们都可以把他们看作流。之后我们来讨论I/O的操作,通过read,我们可以从流中读入数据;通过write,我们可以往流写入数据。

    现在假定一个情形,我们需要从流中读数据, 但是流中还没有数据,(典型的例子为,客户端要从socket读如数据,但是服务器还没有把数据传回来),这时候该怎么办?根据不同的处理办法,可以把IO分为阻塞或者非阻塞的:

    • 阻塞:阻塞是个什么概念呢?比如某个时候你在等快递,但是你不知道快递什么时候过来,而且你没有别的事可以干(或者说接下来的事要等快递来了才能做);那么你可以去睡觉了,因为你知道快递把货送来时一定会给你打个电话(假定一定能叫醒你)。

    • 非阻塞忙轮询:接着上面等快递的例子,如果用忙轮询的方法,那么你需要知道快递员的手机号,然后每分钟给他挂个电话:“你到了没?”

    很明显一般人不会用第二种做法,不仅显很无脑,浪费话费不说,还占用了快递员大量的时间。大部分程序也不会用第二种做法,因为第一种方法经济而简单,经济是指消耗很少的CPU时间,如果线程睡眠了,就掉出了系统的调度队列,暂时不会去瓜分CPU宝贵的时间片了。

    为了了解阻塞是如何进行的,我们来讨论缓冲区,以及内核缓冲区,最终把I/O事件解释清楚。缓冲区的引入是为了减少频繁I/O操作而引起频繁的系统调用 (你知道它很慢的),当你操作一个流时,更多的是以缓冲区为单位进行操作,这是相对于用户空间而言。对于内核来说,也需要缓冲区。

    假设有一个管道,进程A为管道的写入方,B为管道的读出方。假设一开始内核缓冲区是空的,B作为读出方,被阻塞着。然后首先A往管道写入,这时候内核缓冲区由空的状态变到非空状态,内核就会产生一个事件告诉B该醒来了,这个事件姑且称之为“缓冲区非空”。但是“缓冲区非空”事件通知B后,B却还没有读出数据;且内核许诺了不能把写入管道中的数据丢掉这个时候,A写入的数据会滞留在内核缓冲区中,如果内核也缓冲区满了,B仍未开始读数据,最终内核缓冲区会被填满,这个时候会产生一个I/O事件,告诉进程A该阻塞了,我们把这个事件定义为“缓冲区满”。假设后来B终于开始读数据了,于是内核的缓冲区空了出来,这时候内核会告诉A,内核缓冲区有空位了,你可以从长眠中醒来了,继续写数据了,我们把这个事件叫做“缓冲区非满”。但是假如A也没有数据写入了,而B继续读出数据,知道内核缓冲区空了。这个时候内核就告诉B需要阻塞了,我们把这个时间定为“缓冲区空”。

    这四个情形涵盖了四个I/O事件,缓冲区满,缓冲区空,缓冲区非空,缓冲区非满(注都是说的内核缓冲区,且这四个术语都是我生造的,仅为解释其原理而造)。这四个I/O事件是进行阻塞同步的根本。

    然后我们来说说阻塞I/O的缺点。但是阻塞I/O模式下,一个线程只能处理一个流的I/O事件。如果想要同时处理多个流,要么多进程(fork),要么多线程(pthread_create),很不幸这两种方法效率都不高。

    于是再来考虑非阻塞忙轮询的I/O方式,我们发现我们可以同时处理多个流了:我们只要不停的把所有流从头到尾问一遍,又从头开始,这样就可以处理多个流了。但这样的做法显然不好,因为如果所有的流都没有数据,那么只会白白浪费 CPU。这里要补充一点,阻塞模式下,内核对于I/O事件的处理是阻塞或者唤醒,而非阻塞模式下则把I/O事件交给其他对象(后文介绍的select以及 epoll)处理甚至直接忽略。

    为了避免CPU空转,可以引进了一个代理(一开始有一位叫做select的代理,后来又有一位叫做poll的代理,不过两者的本质是一样的)。这个代理比较厉害,可以同时观察许多流的I/O事件,在空闲的时候(即没有I/O事件产生的时候),会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流(即采用同步的方式),避免了忙轮询。 但是依然有个问题,我们从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。即select有O(n)的无差别轮询复杂度,同时处理的流越多,没一次无差别轮询时间就越长。

    而epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们,epoll使得轮询的时间复杂度降低到了O(1)。

    展开全文
  • Linux 阻塞非阻塞 IO简介阻塞非阻塞简介1、阻塞IO2、非阻塞IO 阻塞非阻塞简介 这里的 IO 指的是 Input/Output,也就是输入/输出,是应用程序对驱动设备的输入/输出操作。当应用程序对设备驱动进行操作的时候,...
  • 阻塞IO和非阻塞IO区别

    2015-06-17 10:02:51
    阻塞IO和非阻塞IO区别 (2014-02-28 20:42:32) 转载▼   分类:java  有很多人把阻塞认为是同步,把非阻塞认为是异步;个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全...
  • 阻塞IO和非阻塞IO

    千次阅读 2020-01-15 06:14:39
    一、阻塞IO 因为阻塞IO的存在,导致只能使用一个线程进行等待,等待的线程也会引起额外的资源消耗,引起CPU调度问题。如果数量达到百万级,需要...accept会由阻塞状态变为非阻塞执行状态,会开启两个线程处理获取...
  • 5种IO模型、阻塞IO和非阻塞IO、同步IO异步IO

    万次阅读 多人点赞 2016-10-28 20:01:41
    5种IO模型、阻塞IO和非阻塞IO、同步IO异步IO 看了一些文章,发现有很多不同的理解,可能是因为大家入切的角度、环境不一样。所以,我们先说明基本的IO操作及环境。本文是在《UNIX网络编程 卷1:套接字联网API》...
  • 阻塞IO和非阻塞IO区别 (BIO&NIO)

    千次阅读 2020-11-04 10:30:35
    释义: BIO:是指blocking IO NIO:是指noblocking IO(非阻塞io),也可以理解为newio(新io) 理解新io老io: 司机去问每一个顾客从哪下车(多次阻塞得起线程) 司机去问售票员从哪停车(还是得阻塞,但是不用额外...
  • 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non...
  • 一、阻塞IO模型 最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。当用户线程发出IO请求之后,内核回去看数据是否...二、非阻塞IO模型 当用户线程发起一个read操作后,并不需要等待,而是马上就得到一个结果。
  • 同步IO、异步IO、阻塞IO、非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的。 一、POSIX(可移植操作系统接口)把同步IO操作定义为导致进程阻塞直到IO完成的操作,反之...
  • 阻塞IO、非阻塞IO区别

    千次阅读 2019-03-18 12:21:24
    阻塞IO、非阻塞IO区别 1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合。 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值。 2)实现(实线加小圆):对纯虚函数类(抽象类)的...
  • 这里写目录标题1、IO2、5种IO模型2-1、阻塞IO模型1、典型应用:阻塞socket、Java BIO;...1、典型应用:JAVA7 AIO、高性能服务器应用2、特点:3、IO模型比较阻塞IO调用和非阻塞IO调用、阻塞IO模型和非阻塞IO模型
  • 文章目录【1】同步、异步、阻塞非阻塞的概念【2】阻塞IO模型【3】非阻塞IO模型【4】IO复用模型【5】信号驱动IO【6】异步IO模型【7】各种IO模型的比较 【1】同步、异步、阻塞非阻塞的概念 同步:所谓同步,就是...
  • Linux 阻塞IO和非阻塞IO

    千次阅读 2020-07-01 21:59:25
    2.2 非阻塞IO模型 2.3 信号驱动IO模型 2.4 IO复用模型 2.5 小结 3 异步IO模型 4 五种IO模型对比 1 什么是I/O 程序是由数据+指令构成的,运行程序的过程可以分成下面这几步: 1.将代码加载到内存中...
  • 很多初学者可能分不清楚异步和非阻塞区别,只是在各种场合能听到异步非阻塞这个词。 本文会先介绍并演示阻塞模式,然后引入非阻塞模式来对阻塞模式进行优化,最后再介绍 JDK7 引入的异步 IO,由于网上关于异步 IO ...
  • 2.如何实现非阻塞IO访问 (1)O_NONBLOCKfcntl 3.阻塞式IO的困境 (1)程序中读取键盘 #include <stdio.h> #include <string.h> #include <unistd.h> int main(void) { char b
  • 5种IO模型、阻塞IO和非阻塞IO、同步IO异步IO 看了一些文章,发现有很多不同的理解,可能是因为大家入切的角度、环境不一样。所以,我们先说明基本的IO操作及环境。 本文是在《UNIX网络编程 卷1:套接字联网API》...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 175,193
精华内容 70,077
关键字:

阻塞io和非阻塞io的区别