五种IO模型

五种IO模型

在网络环境下,可以通俗地将IO分为两步:

  1. 数据搬迁

五种IO模型之间的区别就主要在于“等”的方式的不同。

一 阻塞IO(blocking I/O)

当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给线程,用户线程才解除阻塞状态。

拿钓鱼来比喻:
A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候十分专心,不做任何其他的事情。只当有鱼上钩时,才结束掉等的动作,把鱼钓上来。

典型的阻塞IO的例子:

	data = socket.read();

如果数据没有就绪,就会一直阻塞在 read 方法。

二 非阻塞IO(noblocking I/O)

当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是 error 时,它就再次发送 read 操作。 一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它才会将数据拷贝到用户线程。因此,用户线程需要不断地询问内核数据是否就绪,也就是说非阻塞IO不会交出CPU,而是会一直占用CPU。

拿钓鱼来比喻:
B不想将自己的所有时间都花费在钓鱼上,于是他在等鱼上钩的期间也在做其他的事情(一会看看书,一会玩玩手机等)。但是B会每隔一个固定的时间就检查鱼是否上钩,一旦发现有鱼上钩,就把鱼钓上来。

典型的非阻塞IO的例子:

	while(true){
		data = socket.read();
		if(data != error){
			...//处理数据
			break;}

在 while 循环中需要不断地去询问内核数据是否就绪,这样会导致CPU占用率非常高,因此很少使用。

三 多路复用IO(I/O multiplexing)

(这是目前使用比较多的模型,Java NIO 实际上就是多路复用IO,下次单独拿出来写一篇)

在多路复用IO模型中,会有一个线程不断去轮询多个 socket 的状态,只有当 socket 真正有读写时间时,才真正调用实际的IO读写操作。

拿钓鱼来比喻:
C同样也在河边钓鱼,但是C拿了很多根鱼竿,一次性有很多鱼竿在等,C不断地查看每个鱼竿是否有鱼上钩,这样就增加了效率,减少了等待的时间。

在多路复用IO模型中,只需要使用一个线程就可以管理多个 socket,系统不需要建立新的进程或线程,也不必维护这些线程和进程,并且只有在有 socket 读写事件进行时才会使用IO资源,大大减少了资源占用。
IO多路转接是属于阻塞IO,但可以对多个文件描述符进行阻塞监听,所以效率较阻塞IO高。
另外多路复用IO比非阻塞IO模型效率高,是因为:在非阻塞IO中是不断地询问 socket 状态时通过用户线程去进行的;在多路复用IO中轮询每个 socket 状态是在内核中进行的,内核效率要比用户线程高很多。

四 信号驱动IO(signal blocking I/O)

在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的 socket 注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程收到信号后,才会在信号函数中调用IO读写操作来进行实际的IO请求操作。

拿钓鱼来比喻:
D也在河边钓鱼,他给鱼竿上挂了一个铃铛,当有鱼上钩的时候,这个铃铛就会被碰响,D听见铃声就会将鱼钓上来。

五 异步IO(asynchronous I/O)

异步 IO 需要操作系统的底层支持,在 Java 7 中,提供了 Asynchronous IO。

在异步IO模型中,当用户线程发起 read 操作之后,立刻就可以开始去做其他的事。另一方面,从内核的角度,当它受到一个 asynchronous read 之后,它会立刻返回,说明 read 请求已经成功发起了,因此不会对用户线程产生任何 block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它 read 操作完成了。也就说用户线程完全不需要关心整个 IO 操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示 IO 操作已经完成,可以直接去使用数据了。

拿钓鱼来比喻:
E也想钓鱼,但E有事情,于是他雇来了F,让F帮他等待鱼上钩,E去做其他的事情。F钓到鱼后就立马打电话给E,E来把鱼拿走。

也就说在异步 IO 模型中,IO 操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已完成。用户线程中不需要再次调用 IO 函数进行具体的读写。
和信号驱动模型的区别:在信号驱动模型中,当用户线程接收到信号表示数据已经就绪,然后需要用户线程调用 IO 函数进行实际的读写操作;在异步 IO 模型中,收到信号表示 IO 操作已经完成,不需要再在用户线程中调用 IO 函数进行实际的读写操作。

总结

阻塞程度:阻塞IO > 非阻塞IO > 多路转接IO > 信号驱动IO > 异步IO
效率:异步IO > 信号驱动IO > 多路转接IO > 非阻塞IO > 阻塞IO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值