一、前言
了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很多博文有关于对flask上下文管理的剖析都非常到位,当然为了学习flask我也把对flask上下文理解写下来供自己参考,也希望对其他人有所帮助。
二、知识储备
threadlocal
在多线程中,线程间的数据是共享的, 但是每个线程想要有自己的数据该怎么实现? python中的threading.local对象已经实现,其原理是利用线程的唯一标识作为key,数据作为value来保存其自己的数据,以下是demo演示了多个线程同时修改同一变量的值的结果:
#!/usr/bin/env python3# -*- coding:utf-8 -*-# Author:wdimport threadingimport timevalues=threading.local()def run(arg): values.num=arg #修改threading.local对象的name数据 time.sleep(1) print(threading.current_thread().name,values.num) #打印values.numfor i in range(3): th = threading.Thread(target=run, args=(i,), name='run thread%s' % i) th.start()
结果:
run thread0 0
run thread1 1
run thread2 2
结果说明:
从结果中可以看到,values.num的值是不同的,按照普通线程理解因为有sleep存在,在每个线程最后打印values.num时候值应该都是2,但是正是因为threading.local对象内部会为每个线程开辟一个内存空间,从而使得每个线程都有自己的单独数据,所以每个线程修改的是自己的数据(内部实现为字典),打印结果才不一样。
有了以上的设计思想,我们可以自己定义类似于thread.local类,为了支持协程,将其唯一标识改为协程的唯一标识,其实这已经及其接近flask中的Local类了(后续在进行说明):
try: from greenlet import getcurrent as get_ident # 携程唯一标识except ImportError: try: from thread import get_ident except ImportError: from _thread import get_ident # 线程唯一标识class Local(object): def __init__(self): object.__setattr__(self, 'storage', dict()) # 防止self.xxx 递归 object.__setattr__(self, '__get_ident__', get_ident) def __setattr__(self, key, value): ident = self.__get_ident__() # 获取当前线程或协程的唯一标识 data = self.storage.get(ident) if not data: # 当前线程没有数据 data = {key: value} # 创建数据 else: # 当前已经有数据 data[key] = value self.storage[ident] = data # 最后为当前线程设置其标识对应的数据 def __getattr__(self, name): try: return self.storage[self.__get_ident__()].get(name) # 返回name所对应的值 except KeyError: raise AttributeError(name)
functools.partial
partial函数是工具包的一个不常用函数,其作用是给函数传递参数,同时返回的也是这个函数,但是这个函数的已经带了参数了,示例:
新闻热点
疑难解答