网络应用需要处理的无非就是两大类问题,网络I/O,数据计算。相对于后者,网络I/O的延迟,给应用带来的性能瓶颈大于后者。
概念
- 概念1:阻塞与非阻塞
- 概念2:同步与异步
- 概念3:(网络)I/O模型 , 好像一般IO模型就是指网络IO模型
同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式
在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:
- 同步/异步主要针对调用(请求)者(如Client端)
- 所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,调用者会一直等到有return,才会去做下一件事。
- 异步的概念和同步相对。当c端一个异步过程调用发出后,调用者就可以去干其他事。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
- 阻塞/非阻塞主要针对被调用(被请求)者(如S端):
- 阻塞,就是调用我(s端被调用者,函数),我(s端被调用者,函数)没有计算出结果之前,我不会返回。
- 非阻塞,就是调用我(s端被调用者,函数),我(s端被调用者,函数)立即返回,这样的好处是调用者得到返回后可以继续做其他操作,实际的计算结果之后**通过select通知调用者。
- 同步/异步是由c端自己控制,但是S端是否阻塞/非阻塞, C端完全不需要关心.
既然异步IO优势这么明显,那在所有项目里面只使用这一种不就好了?什么情况下会考虑其他的几种IO模型呢?
执行顺序难预期,不利于人类理解,开发调试困难。调用端按a、b、c的顺序发出,在被调用端的返回最终计算结果可能是c、b、a。
我的有道云笔记. 详细讲解四种调用方式:阻塞、非阻塞、同步、异步
(Linux)五种(网络)IO模型
- 详细讲解见:用钓鱼的例子讲Linux五种网络IO模型
-
1)阻塞I/O(blocking I/O)
-
2)非阻塞I/O (nonblocking I/O)
-
被访问者没准备好数据的时候先返回error给访问者,访问进程干一会别的事在发起访问请求。反复前一个步骤(轮询)直到被访者准备好了数据。
-
-
3) I/O复用(select 和poll) (I/O multiplexing)
-
上文的轮询是用户态的操作,消耗大量CPU时间。用户态自己进行访问请求,然后轮询,并自己接收数据。
select轮询和poll是内核级别操作。
select调用可以等待多个socket,当其中任何一个socket的数据准好了,就能返回进行可读。
多路复用I/O用select和poll替换了多路复用I/O。用户态将访问请求交接给select这个帮手,select进行轮询,用户态去select那接收数据。
问题:最终接受数据的顺序,与访问请求的顺序不一致。
对于多路复用,也就是轮询多个socket。钓鱼的时候,我们雇了一个帮手,他可以同时抛下多个钓鱼竿,任何一杆的鱼一上钩,他就会拉杆。他只负责帮我们钓鱼,并不会帮我们处理,所以我们还得在一帮等着,等他把收杆。我们再处理鱼。多路复用既然可以处理多个I/O,也就带来了新的问题,多个I/O之间的顺序变得不确定了,当然也可以针对不同的编号
-
select最老,是对数组套接字的轮询**
-
对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
-
需要维护大量fd
-
基于数组实现,fd存储个数有限
-
-
poll本质上和select没有区别
-
基于链表实现,fd存储个数没有限制
-
-
epoll最新,将socket组织在红黑树中,没有最大并发链接数限制
-
select和epoll就够用了
-
-
4)信号驱动I/O (signal driven I/O (SIGIO))
-
5)异步I/O (asynchronous I/O (the POSIX aio_functions))
-
前四种都是同步IO