目录
一、简述sleep和wait的区别
1、sleep
2、wait
3、区别
二、简述线程池的设计思路,线程池中线程数量的决定因素
1、设计思路
2、线程池中线程数量
三、进程和线程相比,为何更慢
四、简述Linux零拷贝的原理
1、概念
2、优点
3、原理
五、简述epoll和select的区别,epoll为何高效
1、区别
2、epoll高效的原因
六、简述多路I/O复用技术有哪些及其区别
1、多路I/O复用技术
2、区别
一、简述sleep和wait的区别
1、sleep
sleep是一个延时函数,让进程或线程进入休眠。休眠完毕后继续运行。在Linux系统下,sleep函数的参数是秒,而Windows系统中sleep的函数参数是毫秒。例如:
Windows:
#include <windows.h> //首先导入头文件
Sleep(500); //第一个字母大写
//到这里停半秒,然后继续向下执行
Linux:
#include <unistd.h> //首先导入头文件
sleep(5); //停5秒
//到这里停5秒,然后继续向下执行
2、wait
wait是父进程回收子进程PCB资源的一个系统调用。进程一旦调用了wait函数,就立即阻塞自己本身,然后由wait函数自动分析当前进程的某个子进程是否已经退出。当找到一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回。如果没有找到这样一个子进程,wait就会一直阻塞,直到有一个出现为止。函数原型为:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int* status);
子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一起返回。如果不需要结束状态值,则参数status可以设成NULL。
3、区别
(1)sleep是一个延时函数,让进程或线程进入休眠。休眠完毕后继续运行。
(2)wait是父进程回收子进程PCB资源的一个系统调用。
二、简述线程池的设计思路,线程池中线程数量的决定因素
1、设计思路
实现线程池有以下几个步骤:
(1)设置一个生产者消费者队列,作为临界资源;
(2)初始化n个线程,并让其运行起来,加锁去队列里取任务运行;
(3)当任务队列为空时,所有线程阻塞;
(4)当生产者队列来了一个任务后,先对队列加锁,把任务挂到队列上,然后使用条件变量去通知阻塞中的一个线程来处理。
2、线程池中线程数量
影响线程数量的因素:CPU、I/O、并行、并发。
如果是CPU密集型应用,则线程池大小设置为:CPU数目+1
如果是I/O密集型应用,则线程池大小设置为:2*CPU数目+1
最佳线程数目=(线程等待时间与线程CPU时间之比 + 1)*CPU数目
所以线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
那么为什么要创建线程池?创建线程和销毁线程的花销是比较大的,这些时间有可能比处理业务的时间还要长。这样频繁的创建线程和销毁线程,再加上业务工作线程,消耗系统资源的时间,可能导致系统资源不足。同时线程池也是为了提升系统效率。
任务队列可以存放100个任务,此时为空,线程池里面有10个核心线程,若突然来了10个任务,那么刚好10个核心线程直接处理;若来了90个任务,此时核心线程来不及处理,那么有80个任务先入队列,再创建核心线程处理任务;若又来了120个任务,此时任务队列已满,不得已,就需要创建20个普通线程来处理多余的任务。
以上是线程池的工作流程。
三、进程和线程相比,为何更慢
1、进程系统开销显著大于线程开销,线程需要的系统资源更少;
2、进程切换开销比线程大。多进程切换时需要刷新TLB并获取新的地址空间,如何切换硬件上下文和内核栈,多线程切换时只需要切换硬件上下文和内核栈。
3、进程通信比线程通信开销大。进程通信需要借助管道、队列、共享内存,需要额外申请空间,通信繁琐,而线程共享进程的内存,如代码段、数据段、扩展段,通信快捷简单,同步开销更小。
四、简述Linux零拷贝的原理
1、概念
零拷贝描述的是计算机操作系统中,CPU不执行将数据从一个内存区域,拷贝到另外一个内存区域的任务。通过网络传输文件时,这样通常可以节省CPU周期和内存带宽。
2、优点
(1)节省CPU周期,空出的CPU可以完成更多其它任务;
(2)减少了内存区域之间数据拷贝,节省内存带宽;
(3)减少用户态和内核态之间数据拷贝,提升数据传输效率;
(4)应用零拷贝技术,减少用户态和内核态之间的上下文切换。
3、原理
在传统I/O中,用户态空间与内核态空间之间的复制是完全没有必要的,因为用户态空间仅仅起到了一种数据转存媒介的作用,除此之外没有做任何事。
(1)Linux提供了sendfile()用来减少我们的数据拷贝和上下文切换次数。
①发起sendfile()系统调用,操作系统由用户态空间切换到内核态空间(第一次上下文切换);
②通过DMA引擎将数据从磁盘拷贝到内核态空间的输入的socket缓冲区中(第一次拷贝);
③将数据从内核空间拷贝到与之关联的socket缓冲区(第二次拷贝);
④将socket缓冲区的数据拷贝到协议引擎中(第三次拷贝);
⑤sendfile()系统调用结束,操作系统由用户态空间切换到内核态空间(第二次上下文切换)。
根据以上过程,一共有2次上下文切换、3次I/O拷贝,我们看到从用户空间到内核空间并没有出现数据拷贝,从操作系统角度来看,这个就是零拷贝。内核空间出现了复制的原因:通常的硬件在通过DMA访问时期望的是连续的内存空间。
(2)mmap数据零拷贝原理
如果需要对数据进行操作,Linux提供了mmap零拷贝来实现。
五、简述epoll和select的区别,epoll为何高效
1、区别
(1)每次调用select都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多的时候会很大,而epoll保证了每个fd在整个过程中只会拷贝一次。
(2)每次调用select都需要在内核遍历传递进来的所有fd,而epoll只需要轮询一次fd集合,同时查看就绪链表中有没有就绪的fd就可以了。
(3)select支持的文件描述符数量太小,默认是1024,而epoll没有这个限制,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048。
2、epoll高效的原因
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替,而epoll只要判断一下就绪链表是否为空即可,这节省了大量的CPU时间。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把当前进程往设备等待队列中挂一次,而epoll只要一次拷贝,而且把当前进程往等待队列上挂也只挂一次,这也能节省不少的开销。
六、简述多路I/O复用技术有哪些及其区别
1、多路I/O复用技术
select,poll,epoll都是I/O多路复用的机制,I/O多路复用就是通过一种机制,可以监视多个文件描述符,一旦某个文件描述符就绪(一般是读就绪或者写就绪),能够通知应用程序进行相应的读写操作。
2、区别
(1)poll和select不同,通过一个pollfd数组向内核传递需要关注的事件,于是没有描述符个数的限制,pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,所以pollfd数组只需要被初始化一次;
(2)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替,而epoll只要判断一下就绪链表是否为空即可,这节省了大量的CPU时间。
(3)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把当前进程往设备等待队列中挂一次,而epoll只要一次拷贝,而且把当前进程往等待队列上挂也只挂一次,这也能节省不少的开销。