高度模块化:DSO
MPM:多路处理模块
prefork-->一个主进程+多个工作进程,每个工作进程处理多个请求
worker-->一个主进程+多个工作进程,每个工作进程派生多个工作线程,每个线程处理一个请求
event(2.4版本)-->一个主进程+多个工作进程,每个工作进程处理多个请求,不过是根据事件驱动模式来处理请求
系统调用分两个过程:数据从进程-->内核|数据从内核-->进程
只要有一个过程被阻塞,就是同步
异步IO主要应用于文件IO。在同步在编程里,一般是指只有在某个IO操作执行完后可以执行后面的操作。异步则是将某个操作给系统,主线程继续执行别的操作,而由内核完成操作后去负责通知主线程异步操作已经完成。
同步:指进程发出一个过程(功能、函数)调用后,在没有得到结果之前,该调用将不会返回。
异步:指进程发出一个过程(功能、函数)调用后,调用者不能立刻得到结果,但调用会返回。调用完成后,内核通过状态、通知和回调来通知调用者。
同步IO操作会导致请求进程阻塞,直到I/O操作完成;异步I/O操作不导致请求进程阻塞。--同步才有阻塞,异步没有阻塞
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入睡眠状态)。函数只有在得到结果之后才会返回。
非阻塞:指在不能立刻得到结果之前,被调用函数不会阻塞当前线程,而会立刻返回。
同步阻塞-->
进程接到用户请求,发起系统调用,提交给内核
内核接到调用后,并不会返回一个resv函数信号,且进程也会进入睡眠/挂起状态--阻塞
内核调用完毕后,告知进程,进程再次执行系统调用,将数据从内核空间复制到用户空间--阻塞
进程继续执行
同步非阻塞-->
进程接到用户请求,发起系统调用,提交给内核
内核接到调用,至处理完毕钱,进程会不断询问是否调用完毕,期间内核会返回一个错误信息,告知进程调用没有完成,这个过程叫做忙等待
(忙等待状态下,进程不会睡眠/挂起,但是也不会去接收请求)--非阻塞(忙等待)
内核调用完毕后,告知进程,进程再次执行系统调用,将数据从内核空间复制到用户空间--阻塞
进程继续执行
I/O复用-->apache的prefork模型基于select
进程接到用户请求,通过select/poll函数,代它发起系统调用
(select/poll函数的特点是可以同时发起多个系统调用,也就是说可以同时接收多个请求,如此以来,第一阶段的系统调用就不会被阻塞)--伪非阻塞(其实依然是阻塞,只不过阻塞到了select上,select会一次询问所有调用,而不是一个一个询问,因此这种瞬间一次遍历询问,性能并不一定会比同步非阻塞好)
(apache的prefork模型就是基于select函数实现,即一个工作进程通过select函数发起多个请求)
内核调用完毕后,会针对处理完毕调用,返回一个可读信号,由复用函数告知进程,从而使进程发起系统调用,将数据从内核空间复制到用户空间--阻塞
进程继续执行
事件驱动模型-->apache的event和nginx
进程接到用户请求,调用事件驱动回调函数sigaction,然后发起系统调用,提交给内核
内核接到调用后,会返回一个事件信号,告知进程可以先继续执行--非阻塞
当内核调用完毕后,会再返回一个事件信号,告知进程已经调用完毕,可以复制,此时,进程发起系统调用,复制数据到用户空间 -- 阻塞
(返回事件信号分两种:
第一种水平触发-->是不断返回直至进程过来复制
第二种边缘触发-->是通知一次,通知会一直处于提醒等待状态,但是有个超时时间
)
进程继续执行
异步非阻塞-->
进程接到用户请求,调用aio_read函数,提交系统调用的同时,告知内核进程缓冲区的位置/大小等
内核接到调用后,,返回一个信号,告知进程可以先继续执行--非阻塞
当内核调用完毕后,会根据缓冲区的位置和大小,主动将数据复制到缓冲区,同时告知进程,已经处理完毕,故进程不需要再次系统调用 -- 非阻塞
进程继续执行
这5种模型都会在系统调用的第二部分进行复制,那么内存映射mmap就不需要复制,性能更佳!
(内存映射(mmap):内核接到系统调用后,将其放到内核空间中A位置,并告知进程,进程将进程空间映射到内存空间的A位置,从而直接读取,免去了复制的问题,这样子,系统调用的第二部分也不存在阻塞了)