模块设计的目的

Web Service 由于是对多客户端服务的,所以并发处理请求。

在python语言和扩展中存在4种并发模型

- 进程(process)

- 线程(thread)

- 异步(async)

- 协程(coroutine)

werkzeug.locals是针对thread和coroutine设计的

并发的目的是隔离每次请求之间的环境,有很多信息是不能在请求之间共享的

- 请求URL

- 客户端session

- 客户端cookie

所有不能共享的信息都以本地变量的方式保存,比如python.threading.local就是一种实现。

为了兼容多种并发模型,werkzeug提供了自己的local storage实现,即werkzeug.locals.Local类。

不同的并发单元是通过id区别的,并发库会提供获取id的function,常见的名字是get_ident

Local 类

Local类只有两个属性Local.__storage__和Local.__ident_func__

- Local.__storage__存储并发单元的本地数据

- Local.__ident_func__就是获取并发单元id的function

Local.__storage__在初始化的时候被设置成空dict,在运行时key为并发单元的id

本地变量的存取接口和python中对象属性的接口一致,getattr, setattr和delattr操作都只会针对当前的并发单元。

关键代码是:

self.__storage__[self.__ident_func__()]

当目标并发单元被销毁的时候,同时将self.__storage__[self.__ident_func__()]销毁就行了。

注意:并发单元的id是可能重复生成的

LocalStack类

LocalStack是针对wsgi协议的堆栈结构设计的,最先入栈的环境最后被销毁。

enter image description here

实际的堆栈对象是

Local().__storage__[self.__ident_func__()]['stack'] = []

使用list模拟堆栈。

LocalManager类

这个类顾名思义,是用来管理Local对象的。

它有两个作用

- 针对同一个并发单元,设置同一个并发id

- 作为中间件,在应用逻辑执行完毕时销毁所有本地变量

使用注意

在LocalManager的文档中有如下描述

You can pass a local manager multiple locals or add them later
by appending them to manager.locals.

这个说法是不确切的

LocalManager提供了方法LocalManager.get_ident,所有加入到manager.locals中的本地变量都需要用这个函数设置并发单元的id,否则在请求结束时无法正确释放对象。

LocalProxy类

看到这个类的名字的时候我就在想它代理什么?

回顾一下Local类,假设某个并发单元的存储是这样的:

local.__storage__[self.__ident_func__()] = {

'stack': [ req_ctx.request]}

如果程序经常使用到request对象的数据,用localstack._local.stack[0].request就显得繁琐了,不如直接使用request更直观。

LocalProxy代理的就是存储在local.__storage__中的独立对象,并封装了对象的方法,供存取对象的属性和数据。

展开全文
推荐