服务器编程模型

【注】:本篇侧重基本概念理解,不涉及代码实现细节

同步与异步

同步

同步是指程序在执行一次调用时,在没有得到结果之前,程序不会返回,一旦程序返回了,也就得到了返回结果。

异步

异步是指程序在发出调用时,不等调用结果返回就会立即返回,异步通常结合回调实现。(异步往往意味着非阻塞)

总结

同步是自己等结果,异步是别人通知你

阻塞与非阻塞

阻塞

阻塞是指在程序不能立即得到返回结果时(一个时间片以内)当前线程会被挂起。

非阻塞

非阻塞是指在程序调用不能立即得到返回结果时,当前线程不会被挂起。

总结

阻塞程序让出CPU被挂起,非阻塞程序还会继续占用CPU

阻塞与非阻塞 同步与异步的关系

同步阻塞

常见的IO操作,IO阻塞,程序被挂起,在没有得到结果之前之前不会返回。

同步非阻塞

正常编写的程序不涉及到大量耗时的操作都是同步非阻塞

异步阻塞

让程序异步,就是为了为了让其非阻塞,目前还未见过异步阻塞的程序

异步非阻塞

异步非阻塞模型常见的有两种。一种是以node.js为代表的单线程事件+回调的模型,另外一种是以python语言为代表的协程方式。利用协程实现的异步非阻塞本身也是基于事件+回调的模型,只不过此时回调函数利用协程实现后,各个协程可以独自管理自己的状态,避免了大量回调带来的回调地狱


常用的五种服务器模型

同步阻塞模型

  • 最古老的服务器编程模型,效率低下,程序一旦遇到耗时IO便会被阻塞挂起
  • 单进程单线程

多进程模型

  • 多进程模型支持多道程序的并发执行,服务器的并发能力相比同步阻塞模型大大提高
  • 说的并发对单核CPU而言,只是宏观上并行,在微观上仍然是串行
  • 对于单个进程而言仍然是同步阻塞
  • 进程是系统进行资源分配的最小单位,系统分配资源需要从用户态切换到内核态,这是一个耗时的过程,所以对于高并发的场景,基于多进程的服务器并扛不住。

多线程模型

  • 线程是CPU进行调度的最小单位
  • 多个线程共享进程资源
  • 线程切换相比进程切换资源开销要小很多
  • 对于单个线程而言仍然是同步阻塞的。
  • 多线程模型不好的方面是遇到临界资源处理时需要锁机制,加锁会大大降低服务器的并发性能

注:上面三种模型均是同步阻塞的模型

IO多路复用(select/poll)

  • IO多路复用的本质就是在单进程内将原来阻塞的IO的操作改为事件+回调的模式,向操作系统注册感兴趣的事件,当有事件发生时操作系统会返回发生事件的句柄,然后触发对应回调函数即可。
  • select模型是早期Linux支持的IO多路复用模型,效率低下,select的最大文件描述符只支持1024个
  • select返回整个文件句柄的数组,只有遍历数组才能发现哪些句柄发生了事件

epoll模型

  • epoll模型是目前Linux支持IO多路复用最高效的模型,它是select模型的增强版
  • 相比select模型,epoll模型消除了最大文件描述符不再有限制,也就意味着最多可以支持65535个
  • epoll只返回有事件发生的句柄
  • epoll模型的缺点是仍然没有解决异步+回调中的回调地狱问题

上面基本上把常用的五种IO模型给介绍完了,可以看到当服务器模型发展到今天,唯一困扰的问题就是异步IO中的无限回调带来的回调地狱和回调栈撕裂问题,于是目前很多语言开始支持协程,协程是比线程更小的执行单元,不同于进程线程,协程对于操作系统是透明的,它的切换可以由程序员自己显示指定,基于协程解决了回调函数之间的资源传递问题,各个协程独立管理自己的资源。epoll+Coroutine的模型就是Python中高性能web框架Tornado的实现原理。回头会专门整理一篇Tornado模型的实现细节(更侧重代码实现)。

你可能感兴趣的:(网络协议,同步与异步,阻塞与非阻塞,epoll,Python,协程)