silverlining

Python服务器编程

Posted at — 10月 14, 2017

IEEE公布的2017年编程语言排行榜,python高居首位。在百度指数上,python的搜索量也跻身到与java相等的量级,成为最火的语言之一。

img

那么Python适合用来做服务器编程吗?

img

首先,看看哪些公司在用Python作为服务器的主要技术栈?可以看到,其中不缺乏一些用户量庞大的公司。

img

得益于语言的简洁性,python很适合用来进行快速开发,编写出可读性强的程序。那么怎么用python来做服务器编程呢?

从一个例子说起…

img

这是一个简单的回显服务器,服务端每次从请求读取一些字节并返回给客户端。

img

但由于服务器是单进程的,如果一个请求占住了服务器,就没办法处理另一个请求。

img

这次做一些改动,每来一个请求就fork一个进程来处理,这样就不会出现之前的问题。

img

但多进程模型处理不好会出现僵尸进程和孤儿进程,因此父进程需要处理SIGCHILD信号来收集退出的子进程的信息。

img

socketserver模块中ForkingMixIn收集子进程的例子:

img

原始的CGI程序就是使用这种方式,对于每个请求都fork进程来解释cgi程序。

img

不过随着请求数量的变多,fork进程所带来的开销往往很大。

img

所以CGI不仅慢…

img

而且

img

甚至

img

后来出现了FastCGI,它与CGI的区别,就是更Fast(误),它是一个常驻进程,预先启动多个cgi进程来等待处理请求。

img

不同于FastCGI,Apache搞了一套mod_python,使得python解释器可以嵌入在apache进程。

img

后来PEP 333中定义了WSGI,成为沿用至今的Python web开发的标准协议。

img

应用WSGI协议的一个示例:

img

绝大部分的python web开发框架都遵守了这套标准:

img

gunicorn是一个著名的wsgi http服务器,它采用pre-fork模型来处理和转发请求。(原图出处

img

img

img

gunicorn包含许多种worker模型:(原图出处

img

img

img

img

抛开多进程,现在来看多线程的模型,该方案用线程代替进程来处理每一个请求:

img

但是为什么许多人说python的多线程是个鸡肋呢?看下面同样的代码,用同步的方式和多线程的方式执行,多线程的代码却执行的更慢…

img

这到底是什么回事?

img

这就要说到python中的GIL了,由于GIL的制约,多线程很难充分利用cpu的性能(原图引用

img

话虽如此,多线程在IO密集型应用上还是有不少用武之地的。下面是多线程在服务器编程的其中一些应用(原图引用

Actor模型

img

img

生产者-消费者

img

img

img

concurrent.future在PEP 3148中被定义,它提供了更简单的多进程/多线程API

img

img

img

img

在很长的一段时间,多进程/多线程的模型都应用的很好,但是

img

img

这时候更适合服务器编程的IO多路复用模型开始被广泛应用:

img

img

img

img

img

基于事件驱动的异步模型对服务器的资源的有效利用率显然易见(原图出处

img

衍生了大量的异步网络框架

img

img

img

img

img

img

img

img

img

在Python 3.4后出现了专门处理异步IO的标准库asyncio

img

img

img

img

而在随后的Python 3.5后出现了协程语法糖async/await

img

img

虽然asyncio成为标准库,但它使用方法却较为复杂,不便于使用,也有人提议要asyncio提供更简洁的接口,也有不少的替代库出现

img

img

总的来说,服务器编程经历了从开始的简单到后来的复杂化最终慢慢演变到简单的方式上。

img

img