进程| 线程 | 阻塞 | 阻塞&非阻塞 和 同步&异步

阻塞&非阻塞

阻塞IO数组

调用以后必定要等到系统内核完成全部的操做以后才结束,所以它的缺点:CPU等待IO,处理能力得不到充分利用。数据结构

非阻塞IO多线程

为了解决阻塞IO带来的一些问题,内核提供了非阻塞IO,非阻塞IO的差异是调用以后会当即返回。缺点:非阻塞IO当即返回并非业务层指望的数据,而仅仅是调用的状态,为了获取完整的数据,应用程序须要重复调用IO操做确认,即轮询。异步

轮询线程

常见的三种轮询方式:select、poll和epoll。进程

一、select事件

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

参数解释资源

  • nfds:被监听的文件描述符总数
  • readfds writefds exceptfds : 可读、可写、异常事件的accept到对应的文件描述符集合
  • fd_set:是一个整形数组,每个元素的每一位来表示每个文件描述符是否有相应的事件发生。(0没有1有)数组的长度由FD_SETSIZE决定
  • timeout:轮询的时间片

经过设置或者检查存放fd(文件标识符)标志位的数据结构进行处理(select对应于内核的sys_select调用):1.将第二、三、4个参数指向的fd_set拷贝到内核;2.对每一个被set对描述符调用进行poll,并记录在临时结果中(fdset)同步

缺点是:it

  • 单个进程的fd监视数量有限
  • 须要维护一个存放fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
  • 每次select操做须要初始化fdset,由于select的第二、三、4参数既是输入参数也是输出参数,在内核中会被修改
  • socker的扫描是线性扫描

二、poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

poll和select的实现机制相似,对应内核的sys_poll,可是传递的是pollfd数组,接着对pollfd数组进行poll。

优势:

  • pollfd数组只须要被初始化一次,由于pollfd的events字段和revents分别用于标示关注的事件和发生的事件
  • 对描述符个数没有限制,poll经过一个pollfd数组向内核传递须要关注的事件

三、epoll

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

相对于select和poll的遍历查询,epoll是真实利用了执行回调和事件通知的机制,充分利用CPU,所以效率比较高。

四、总结

总的来讲,轮询技术知足非阻塞IO确保完整数据获取的需求,当时对于应用程序来讲,它仍然是同步,由于它必须等待IO彻底返回。等待IO期间,CPU要么遍历文件描述符的状态,要没用于休眠等待事件发生。

2、同步&异步

同步IO:同步IO比较简单,就是简单的顺序执行,其实阻塞和非阻塞都属于同步IO。

异步IO:这里拿Node举例,在Node中,咱们知道异步是它的一大特点,那它到底有哪些好处呢?

  • 一、从请求时间上来讲,假设某个资源须要获取a,b两个地方的资源,a资源须要时间M毫秒,b资源须要时间N毫秒,此时:同步须要sum(M,N),异步须要max(M,N)
  • 2 从资源消耗来讲,异步远离阻塞,单线程避免了多线程容易出现的死锁等各类异常状况

咱们期待的异步是:当咱们应用程序发起阻塞请求,不须要轮询技术,直接处理下一个任务;当阻塞请求完成以后,将数据传递到应用程序。在Linux下存在这种异步IO即AIO。

若是咱们本身去实现异步IO,则能够经过线程池+轮询技术来实现数据的获取。例如如今应用程序发起了一个阻塞请求,咱们能够以下处理:

  1. 让a线程利用轮询技术去处理阻塞调用
  2. 让b线程去执行计算处理
  3. 当a线程的处理结果经过线程间共享发送给b
  4. 这样,就完成了异步IO。

3、总结

经过上面的介绍,咱们须要知道的是:阻塞&非阻塞和异步&同步是不能混为一谈的,非阻塞本质上仍是同步,它所谓的返回只是状态并非数据。

因为阻塞&非阻塞和异步&同步的概念十分相似,这里就其作了一个简单介绍

相关文章
相关标签/搜索