同步、异步、阻塞、非阻塞与服务器


最近在折腾服务器框架相关问题,学了东西不记下来很快会忘记……html

OS中的同步、异步、阻塞、非阻塞

OS的I/O流程是这样的:python

  1. CPU发出I/O操做的通知;
  2. 文件系统或其余会调用相关设备执行这些操做;
  3. 最后当数据到达用户空间后发出一个中断的完成标志;

在这个从CPU发出调用到收到完成标志的过程当中就存在一个时间差,如今就有了两个重要的概念:完成标志与时间差。服务器

  • 同步与异步是针对获取完成标志
  • 阻塞与非阻塞是针对时间差

因此有这样的定义:多线程

  • 同步与异步:获取完成标志的方式。若是是采用轮询的方式监测I/O操做是否完成称为同步,而以经过回调通知的方式得到完成标志则称为异步。
  • 阻塞与非阻塞:在那段时间差的过程当中,CPU有没有处理别的事情,若是处理过别的事情则是非阻塞,若是并无处理过别的事情则是阻塞。

I/O控制方式有哪几种?
1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)--> 轮询
3) I/O复用(select 和poll) (I/O multiplexing)
4)信号驱动I/O (signal driven I/O (SIGIO))
5)异步I/O (asynchronous I/O (the POSIX aio_functions)) --> 回调
看图便于理解:

出自:Linux的五种I/O模式并发

几种常见服务器模型:

下面咱们谈谈服务器,服务器模型也能够基于异步、同步、阻塞、非阻塞这四个概念框架

  • 同步式:一次处理一个请求,其他请求处于等待状态
  • 每请求/每进程: 为每一个请求启动一个进程【不具有扩展功能,系统志愿有限】
  • 每请求/每线程:为每一个请求启动一个线程【每一个线程占必定内存,故受限于内存,还会拖慢服务器】【Apache就是采用的这种方式】
  • 事件驱动:Node与Nginx采用事件驱动方式而不建立新线程【省去了线程建立/删除的系统开销以及线程上下文切换,因此可以处理更多的链接】【python的Twisted,Ruby的Event Machine以及Perl的AyEvent也是事件驱动,可是他们并非很成功】

须要注意的是对于高并发的程序每每采用“同步非阻塞”而不是“多线程的同步阻塞”,在合理设计任务调度的不一样阶段可以使得并发数远大于并行数,须要注意的是在高并发情况下为每一个任务建立一个线程的开销很大,因此并不采用多线程的同步阻塞。异步

并发:同时进行的任务数量
并行:可同时工做的物理资源(CPU核数等等)async

另外,有个概念是异步IO,其主要是说在同一线程中当遭遇IO时,并不等待而是执行下面的操做直到IO操做完成后再切回当前,其实就是同步非阻塞,在廖雪峰老师的博客中提到这样一个模型:
异步IO模型须要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”这一过程:高并发

loop = get_event_loop()
while True:
    event = loop.get_event()
    process_event(event)

消息模型其实早在应用在桌面应用程序中了。一个GUI程序的主线程就负责不停地读取消息并处理消息。全部的键盘、鼠标等消息都被发送到GUI程序的消息队列中,而后由GUI程序的主线程处理。oop

因为GUI线程处理键盘、鼠标等消息的速度很是快,因此用户感受不到延迟。某些时候,GUI线程在一个消息处理的过程当中遇到问题致使一次消息处理时间过长,此时,用户会感受到整个GUI程序中止响应了,敲键盘、点鼠标都没有反应。这种状况说明在消息模型中,处理一个消息必须很是迅速,不然,主线程将没法及时处理消息队列中的其余消息,致使程序看上去中止响应。

消息模型是如何解决同步IO必须等待IO操做这一问题的呢?当遇到IO操做时,代码只负责发出IO请求,不等待IO结果,而后直接结束本轮消息处理,进入下一轮消息处理过程。当IO操做完成后,将收到一条“IO完成”的消息,处理该消息时就能够直接获取IO操做结果。

在“发出IO请求”到收到“IO完成”的这段时间里,同步IO模型下,主线程只能挂起,但异步IO模型下,主线程并无休息,而是在消息循环中继续处理其余消息。这样,在异步IO模型下,一个线程就能够同时处理多个IO请求,而且没有切换线程的操做。对于大多数IO密集型的应用程序,使用异步IO将大大提高系统的多任务处理能力。

相关资料

Linux的五种I/O模式
廖雪峰Python-异步I/O
同步,异步,阻塞,非阻塞以及几种常见的服务器模型

相关文章
相关标签/搜索