-
Notifications
You must be signed in to change notification settings - Fork 3
资源管理
使用Veil框架的应用程序是基于进程模型的。其含义是两方面:
- Veil不使用线程做为处理并发的手段
- Veil不用Thread Local管理资源,而是把资源的引用直接做为static的变量,也就是全局变量
这两个方面是相辅相成的。如果使用了线程,那么全局的变量就可能被线程并发访问,就必然需要引入Thread Local进行区隔。
应用程序的代码会以三种方式被执行:WEB调用,命令行调用,后台任务调用。每一种执行方式都是以独立的进程来实现的。
- 具体的措施一是底层使用的应用服务器是tornado。tornado就是一个基于进程的应用服务器,也就是一个进程一次只能处理一个请求。如果需要同是并发处理多个请求,需要前置一个nginx的反向代理服务器来round robin地方式把请求依次派发给不同的后端tornado服务器。
- 除了Web服务器是进程模型,另外一个牵涉到进程的是命令行。@script可以向框架注册命令行脚本。这些脚本显然也是以一个进程的方式独立运行的。
- 还有一个地方会启动进程的是后台任务。Veil使用pyres实现后台任务的调度。而pyres对于每个后台任务也是以子进程的方式隔离执行的。
单进程意味着,当前python解释器内的全局变量与当前处理的请求有一一对应的关系。这样使得资源的管理变得更加容易。比如说每个进程对应一个数据库连接,一直保持联通的状态。这样每次处理请求的时候,不再需要打开关闭数据库连接。也不需要担心两个并发的请求共享了同一个数据库连接。类似的还有以全局状态代表当前请求处理上下文,比如说当前请求的locale通过以下方式全局设置:
with require_current_locale_being(locale):
# some operation
通过这个api就把一个locale置成了全局状态。所有使用get_current_locale的地方都可以得到这个设置的locale。类似这样的全局状态有很多。虽然从严格地隔离依赖的角度来说,这样的全局状态可能使得某些底层的utility方法的作者,能够很邪恶的通过get_current_http_request
之类的api轻易地跨过分层的限制获得WEB层才应该知道的状态。但是我们的意见是,依赖的管理最重要的时靠代码的作者自律,其次是依赖检查工具(这个方面Veil框架也提供了直接的支持)。强制用IoC等方式反转注入外部资源,除了让简单的代码变得更加罗嗦外,未必带来了多少直接的好处。使用参数把http_request传给某个utility方法,和让utility方法直接依赖get_current_http_request
,两者都是对WEB形成了依赖关系,从工具的角度来说后者其实更加容易被识别出来。
理由很简单,就是为了简单。相比进程模型,线程模型有更大的灵活性,但是也有更大的复杂性。相比全局状态,精细地管理每个线程,乃至每个请求内部的context,当然精细管理更灵活,但是也更复杂。进程模型做为由操作系统和python解释器定义的物理隔离容器,线程和开独立context的做法更像在这个大容器内再打小格子。在如今单线程高效能web服务器白菜化的今天,以及python的GIL并未完全被解决的现实下,简单直接的进程全局管理模型,未尝不值得一试。