首页 > 编程 > Python > 正文

Flask核心机制之上下文源码剖析

2020-02-16 00:19:04
字体:
来源:转载
供稿:网友

一、前言

了解过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函数是工具包的一个不常用函数,其作用是给函数传递参数,同时返回的也是这个函数,但是这个函数的已经带了参数了,示例:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表