flask高阶
内容:
1.进程线程复习
2.flask多线程的问题
3.线程隔离
4.LocalStack
5.flask上下文整理
6.多app应用
1.进程线程复习
(1)进程
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元
简单说进程就是操作系统调度分配资源的单位,每一个应用程序至少有一个进程
(2)线程
线程可以说是进程的一部分,可以有一个线程也可以有多个线程
只用进程管理CPU资源,粒度太大了,需要更小的单元来管理,就出现了线程
(3)进程与线程的区别
- 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位
- 线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程
- 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
- 资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮
- 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程
- 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
- 线程是处理器调度的基本单位,但是进程不是
(4)多线程的好处
- 多线程可以更加充分的利用CPU的性能优势
- 实现异步编程
(5)其他
对于普通python(GIL)、node.js来说一般都是单进程单线程的
- 对于CPU密集型程序,多线程无优势
- 对于IO密集型程序,多线程有优势
2.flask多线程的问题
(1)flask与webserver
flask自带的run方法其实是自己的一个服务器,只是供我们测试调试用的,真正上线后我们要用webserver去运行flask而不是用flask自带的运行方法
另外flask自带的是单进程单线程的,不能同时处理多个请求,用webserver可以有效提高性能
常见的webserver:nginx、apache、IIS等
(2)flask多线程的问题
flask中可以开启多线程,开启方法:run方法中有一个threaded参数,设置为True开启多线程
开启之后可能会导致这个问题:

flask中通过线程隔离来解决这个问题
3.线程隔离
(1)flask线程隔离基本原理
现有全局变量request=None
- 在线程1中 request=Request()
- 在线程2中 request=Request()
- 在线程3中 request=Request()
想取线程1的request, 现在的情况下肯定无法做到
解决办法:全局变量改为dict, 每一个线程都有对应的自己的key, 并将request作为value存放。falsk的线程隔离技术也是基于类似的原理实现的。
(2)源码
siet-package/werkzeug/local.py 中的Local类:
class Local(object):
__slots__ = ('__storage__', '__ident_func__') def __init__(self):
object.__setattr__(self, '__storage__', {}) # __storge__ 实现空的字典
object.__setattr__(self, '__ident_func__', get_ident) # get_ident是获取当前线程id号的 函数 def __iter__(self):
return iter(self.__storage__.items()) def __call__(self, proxy):
"""Create a proxy for a name."""
return LocalProxy(self, proxy) def __release_local__(self):
self.__storage__.pop(self.__ident_func__(), None) def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name) def __setattr__(self, name, value):
ident = self.__ident_func__() # 取当前线程的 线程id号,
storage = self.__storage__ # 类本身的字典
try:
storage[ident][name] = value # 把当前线程id号存起来
except KeyError:
storage[ident] = {name: value} def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
Local类用当前线程的id号当作key存储不同的线程,不同线程操作该对象时互不影响,Local类就是线程隔离的对象
Local隔离实例:
from werkzeug.local import Local
import threading, time my_obj = Local()
my_obj.b = 1 def worker():
my_obj.b = 2
print('in sub thread b is:' + str(my_obj.b)) # subthread1 = threading.Thread(target=worker, name='subthread1')
subthread1.start() time.sleep(1) print('my_obj.b is : {}'.format(my_obj.b)) #
(3)线程隔离的意义
使用线程隔离使当前线程能正确引用到自己创建的对象,而不是引用到其他线程所创建的对象
4.LocalStack
(1)源码
class LocalStack(object):
def __init__(self):
self._local = Local() def __release_local__(self):
self._local.__release_local__() def _get__ident_func__(self):
return self._local.__ident_func__ def _set__ident_func__(self, value):
object.__setattr__(self._local, '__ident_func__', value)
__ident_func__ = property(_get__ident_func__, _set__ident_func__)
del _get__ident_func__, _set__ident_func__ def __call__(self):
def _lookup():
rv = self.top
if rv is None:
raise RuntimeError('object unbound')
return rv
return LocalProxy(_lookup) def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, 'stack', None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv def pop(self):
"""Removes the topmost item from the stack, will return the
old value or `None` if the stack was already empty.
"""
stack = getattr(self._local, 'stack', None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self._local)
return stack[-1]
else:
return stack.pop() @property
def top(self):
"""The topmost item on the stack. If the stack is empty,
`None` is returned.
"""
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
(2)LocalStack和Local关系
- Local使用字典实现线程隔离
- LocalStack封装了Local,实现了线程隔离的栈结构
(3)使用LocalStack
from werkzeug.local import LocalStack # 栈 先进后出
# LocalStack常用方法: push pop top s = LocalStack()
s.push(1)
print(s.top) # top只会取出元素不会删除
print(s.top)
print(s.pop()) # pop取出元素并删除
print(s.top) s.push(1)
s.push(2)
print(s.top)
print(s.top)
print(s.pop())
print(s.top)
from werkzeug.local import LocalStack # 栈 先进后出
from threading import Thread
import time my_stack = LocalStack()
my_stack.push(1)
print("in main thread after push, value is: " + str(my_stack.top)) # def worker():
# 新线程
print("in new thread before push, value is: " + str(my_stack.top)) # None
my_stack.push(2)
print("in new thread after push, value is: " + str(my_stack.top)) # new_t = Thread(target=worker, name="new thread")
new_t.start()
time.sleep(1) # 主线程
print("finally, in main thread value is: " + str(my_stack.top)) #
5.flask上下文整理

(1)请求上下文
from flask import Flask,request,session,g,current_app
app = Flask(__name__)
@app.route('/',methods=['GET',"POST"])
def index():
# request是 LocalProxy 的对象
print(request) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request
request.method # LocalProxy.__getattr__ -->
# str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request
# getattr(self._get_current_object(), name) --> ctx.request.method
request.path # ctx.request.path
print(session) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.session
print(g) # 执行g对象的__str__
return "index"
if __name__ == '__main__':
# 1. app.__call__
# 2. app.wsgi_app
app.wsgi_app
app.request_class
app.run()
(2)应用上下文
from flask import Flask,request,session
app = Flask(__name__)
@app.route('/',methods=['GET',"POST"])
def index():
# request是 LocalProxy 的对象
print(request) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request
request.method # LocalProxy.__getattr__ -->
# str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request
# getattr(self._get_current_object(), name) --> ctx.request.method
request.path # ctx.request.path
print(session) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.session
return "index"
if __name__ == '__main__':
# 1. app.__call__
# 2. app.wsgi_app
app.wsgi_app
app.run()
from flask import Flask,request,g app = Flask(__name__) @app.before_request
def before():
g.permission_code_list = ['list','add'] @app.route('/',methods=['GET',"POST"])
def index():
print(g.permission_code_list)
return "index" if __name__ == '__main__':
app.run()
(3)请求上下文及应用上下文
a. 请求上下文:
- request
- session b. 应用上下文:
请求流程:
_request_ctx_stack.local = { } _app_ctx_stack.local = { } 1. 请求到来 ,有人来访问
# 将请求相关的数据environ封装到了RequestContext对象中
# 再讲对象封装到local中(每个线程/每个协程独立空间存储)
# ctx.app # 当前APP的名称
# ctx.request # Request对象(封装请求相关东西)
# ctx.session # 空
_request_ctx_stack.local = {
唯一标识:{
"stack":[ctx, ]
},
唯一标识:{
"stack":[ctx, ]
},
} # app_ctx = AppContext对象
# app_ctx.app
# app_ctx.g _app_ctx_stack.local = {
唯一标识:{
"stack":[app_ctx, ]
},
唯一标识:{
"stack":[app_ctx, ]
},
} 2. 使用
from flask import request,session,g,current_app print(request,session,g,current_app) 都会执行相应LocalProxy对象的 __str__ current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session')) current_app = LocalProxy(_find_app)
g = LocalProxy(partial(_lookup_app_object, 'g')) 3. 终止,全部pop 问题1:多线程是如何体现?
问题2:flask的local中保存数据时,使用列表创建出来的栈。为什么用栈?
- 如果写web程序,web运行环境;栈中永远保存1条数据(可以不用栈)。
- 写脚本获取app信息时,可能存在app上下文嵌套关系。
from flask import Flask,current_app,globals,_app_ctx_stack app1 = Flask('app01')
app1.debug = False # 用户/密码/邮箱
# app_ctx = AppContext(self):
# app_ctx.app
# app_ctx.g app2 = Flask('app02')
app2.debug = True # 用户/密码/邮箱
# app_ctx = AppContext(self):
# app_ctx.app
# app_ctx.g with app1.app_context():# __enter__方法 -> push -> app_ctx添加到_app_ctx_stack.local
# {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438>]}}
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG']) with app2.app_context():
# {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438> ]}}
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG']) print(current_app.config['DEBUG'])
6.多app应用
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask, current_app app1 = Flask('app01')
app2 = Flask('app02') @app1.route('/index')
def index():
return "app01" @app2.route('/index2')
def index2():
return "app2" # http://www.oldboyedu.com/index --> app1
# http://www.oldboyedu.com/admin/index2 --> app2
app= DispatcherMiddleware(app1, {
'/admin': app2,
}) if __name__ == "__main__":
run_simple('localhost', 5000, app)
flask高阶的更多相关文章
- python 常用的高阶函数
前言 高阶函数指的是能接收函数作为参数的函数或类:python中有一些内置的高阶函数,在某些场合使用可以提高代码的效率. map() map函数可以把一个迭代对象转换成另一个可迭代对象,不过在pyth ...
- python基础之常用的高阶函数
前言 高阶函数指的是能接收函数作为参数的函数或类:python中有一些内置的高阶函数,在某些场合使用可以提高代码的效率. map() map函数可以把一个迭代对象转换成另一个可迭代对象,不过在pyth ...
- Python高阶用法总结
目录 1. lambda匿名函数 1.1 函数式编程 1.2 应用在闭包 2. 列表解析式 3. enumerate内建函数 4. 迭代器与生成器 4.1 迭代器 4.3 生成器 5. 装饰器 前言: ...
- 08 . Python3高阶函数之迭代器、装饰器
Python3高阶函数之迭代器.装饰器 列表生成式 推导式就是构建比较有规律的列表,生成器. 孩子,我现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里 ...
- c#语言-高阶函数
介绍 如果说函数是程序中的基本模块,代码段,那高阶函数就是函数的高阶(级)版本,其基本定义如下: 函数自身接受一个或多个函数作为输入. 函数自身能输出一个函数,即函数生产函数. 满足其中一个条件就可以 ...
- swift 的高阶函数的使用代码
//: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...
- JavaScript高阶函数
所谓高阶函数(higher-order function) 就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 下面的例子接收两个函数f()和g(),并返回一个新的函数用以计算f(g ...
- 分享录制的正则表达式入门、高阶以及使用 .NET 实现网络爬虫视频教程
我发布的「正则表达式入门以及高阶教程」,欢迎学习. 课程简介 正则表达式是软件开发必须掌握的一门语言,掌握后才能很好地理解到它的威力: 课程采用概念和实验操作 4/6 分隔,帮助大家理解概念后再使用大 ...
- python--函数式编程 (高阶函数(map , reduce ,filter,sorted),匿名函数(lambda))
1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层的函数,可以把复杂的任务分解成简单的任务,这种一步一步的分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...
随机推荐
- squeeze()
一.说明 B = squeeze(A),B与A有相同的元素,但所有只有一行或一列的维度(a singleton dimension)被去除掉了.A singleton dimension的特征是siz ...
- 清除的通用样式 css
/*公共样式--开始*/ html, body, div, ul, li, h1, h2, h3, h4, h5, h6, p, dl, dt, dd, ol, form, input, textar ...
- 学会从后往前遍历,例 [LeetCode] Pascal's Triangle II,剑指Offer 题4
当我们需要改变数组的值时,如果从前往后遍历,有时会带来很多麻烦,比如需要插入值,导致数组平移,或者新的值覆盖了旧有的值,但旧有的值依然需要被使用.这种情况下,有时仅仅改变一下数组的遍历方向,就会避免这 ...
- [转载]PHP 连接 Rabbitmq 实例代码
转自 http://www.dahouduan.com/2017/11/23/php-rabbitmq-demo/ 接下来我们用 php 连接 rabbitmq 玩一玩.还没有安装 rabbitmq ...
- ruby -检查json数据类型
HashObj={","language"=>"zh","make"=>"Apple"," ...
- enjoy dollar vs cash dollar
當 enJoy 卡 客 戶 憑 enJoy 卡 於 enJoy 卡 「 特 約 商 戶 」 簽 賬 消 費 , 累 積 之 enJoy Dollars 及 Cash Dollars 可 在 同 一 交 ...
- ZZ ? ?: 回?做??的十年技?生涯(?文,非??慎入)
元音字母 身份 用户 文章 1409 星座 双子座 积分 14420 等级 灵樨(8) 发信人: fafe (元音字母), 信区: WorkLife 标 题: 回顾做码农的十年技术生涯(长文,非码农 ...
- maven 知识点2
maven 命令: table th:first-of-type { width: 500px; } table th:nth-of-type(2) { } 命令 含义 mvn help:effect ...
- native app、web app、hybrid app、react-native 区别
Native App:指的是原生应用程序,一般依托于操作系统,有很强的交互. 技术:Objective-C Java Native App开发的优点 提供最佳的 户体验 拥有系统级别的通知或提醒 可以 ...
- requestAnimationFrame 提高动画性能的原因
与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机.具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新 ...