- 如何理解I/O多路复用
- 线程和进程的区别
通常IO操作都是阻塞I/O的, 比如说当你调用read时,如果没有数据收到,那么线程或者进程就会被挂起,直到收到数据。
这样,当服务器需要处理1000个连接的的时候,而且只有很少连接忙碌的,那么会需要1000个线程或进程来处理1000个连接,而1000个线程大部分是被阻塞起来的。由于CPU的核数或超线程数一般都不大,比如4,8,16,32,64,128,比如4个核要跑1000个线程,那么每个线程的时间槽非常短,而线程切换非常频繁。 线程的内存开销,以及线程切换的上下文开销会很高。
那么,我们就要引入非阻塞I/O的概念,当你调用read时,如果有数据收到,就返回数据,如果没有数据收到,就立刻返回一个错误。这样是不会阻塞线程了,但是你还是要不断的轮询来读取或写入。
于是,我们需要引入IO多路复用的概念。多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。
简单来说,进程是资源分配的最小单位,线程是CPU调度的最小单位。从计算机的角度,进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。
因为CPU的处理速度远远快于寄存器,RAM等设备,所以多个任务执行的时候,是把CPU的时间分割成时间片,来轮流处理程序。对于程序而言,相关的资源被称作为程序的上下文,当程序执行结束,或者分配的CPU执行时间用完了,那它就要被切换出去。在切换出去的最后一步工作就是保存程序的上下文,等待下一次被CPU处理。
总结起来所有的任务都是一个个被执行的,轮流的方法就是先加载程序A的上下文,再执行程序A,保存程序A的上下文。加载下一个程序B的上下文...
基于这样的背景,线程和进程的概念就出来了。他们是对应的CPU时间段的描述。进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文。而线程是什么呢?进程的颗粒度太大,每次都要有上下文的调入,保存,调出。我们可以讲进程对应的整个程序拆分成多个块,CPU执行程序的时候,分别执行这些小块程序。也就是说,线程是共享了进程的上下文环境的更为细小的CPU时间段。