【flask】理解flask的几个难点,难啃的骨头,线程隔离啥的

news2024/10/6 12:28:27

1.三种路由和各自的比较
2.配置文件所有的字母必须大写
3.if __name__的作用
4.核心对象循环引用的几种解决方式–难
5.Flask的经典错误
6.上下文管理器
7.flask的多线程和线程隔离

三种路由

方法1:装饰器 python C#, java 都可以用这种方式

from flask import Flask
app = Flask(__name__)

@app.route('/hello')
def hello():
	return 'Hello world!'

app.run(debug=True)

方法2: 注册路由 php python

from flask import Flask
app = Flask(__name__)

//@app.route('/hello')
def hello():
	return 'Hello world!'

app.add_url_rule('/hello', view_func=hello)

app.run(debug=True)

方法3:python 特有的规则

from flask.views import View, MethodView
from flask import Flask, render_template, request

app = Flask(__name__)


class MyView(MethodView):
    def get(self):
        return render_template('index.html')

    def post(self):
        username = request.form.get('username')
        password = request.form.get('password')
        if username == "gp" and password == "mypassword":
            return '密码正确'
        else:
            return '密码错误'


app.add_url_rule('/', endpoint='login', view_func=MyView.as_view('login'))


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

它的过程是通过View的as_view -> MethodView中的dispatch_request -> 具体的get、post等方法。

看一看flask 是如何实现的

class View:
   methods: t.Optional[t.List[str]] = None
   provide_automatic_options: t.Optional[bool] = None
   decorators: t.List[t.Callable] = []def dispatch_request(self) -> ResponseReturnValue:
       raise NotImplementedError()@classmethod
   def as_view(
       cls, name: str, *class_args: t.Any, **class_kwargs: t.Any
  ) -> t.Callable:
       def view(*args: t.Any, **kwargs: t.Any) -> ResponseReturnValue:
           self = view.view_class(*class_args, **class_kwargs)  # type: ignore
           return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)if cls.decorators:
           view.__name__ = name
           view.__module__ = cls.__module__
           for decorator in cls.decorators:
               view = decorator(view)
               
       view.view_class = cls  # type: ignore
       view.__name__ = name
       view.__doc__ = cls.__doc__
       view.__module__ = cls.__module__
       view.methods = cls.methods  # type: ignore
       view.provide_automatic_options = cls.provide_automatic_options  # type: ignore
       return view

实际上flask通过as_view方法,返回一个函数,这个函数就是我们需要绑定的视图函数,实现由类到函数的变化过程。

通过把cls绑定到view函数的view_class属性上面,实现view.view_class(*class_args, **class_kwargs)

来达到传递参数的目的,这正是python魅力之所在。就是用的闭包,或者装饰器了。和第一种方法类型,不过一个显示,一个隐式而已。

配置文件所有的字母必须大写

开发环境和测试环境以及生成环境的参数不同,那么如何区分这三个环境呢,if else 获取不一样的环境? 不是的,应该让三个环境相近,而使用配置文件将他们分开, 然后 设置 git ignore, 各自走各自的配置文件
在项目根路径下设置config.py

DEBUG=True

在面的启动文件

app = Flask(__name__)
# 加载配置项
app.config.from_object("config")
# 读取
app.config["DEBUG"]

注意flask 规定,只能用全大写,否则key error

if __name__的作用

是入口文件,增加了这个判断,能够确保入口文件里面的代码只在入口文件执行。

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

手动启动很好理解,因为他做了入口。
但是生产环境下是nginx+uwsgi,它是被uwsgi所加载的模块。入口文件变成了uwsgi,此时如果没有 if __name__的判断,会使web服务器启动两遍。一个是uwsgi的,一个是 开发中的python入口文件的,flask的内置服务器。

视图函数的return和普通函数的return有什么区别么?

有,不是一个简单的普通函数的return,是返回了一个response的响应对象。
视图函数,不会只返回类似 helloworld的字符串,
而是返回包含 status code 200,404, 301, content-type http headers,默认text/html
以及return的文本。

它等于

@app.route('/hello')
def hello():
	return 'helloworld'
@app.route('/hello')
def hello():
	return '<html></html>'
@app.route('/hello')
def hello():
	headers = {
		'content-type':'text/plain'
	}
	response = make_response('<html></html>',200)
	response.headers=headers
	return response 

最后一个会解析出html 因为他当成 text/plain 普通文本,而不是html文本了。

@app.route('/hello')
def hello():
	
	return '<html></html>', 301,headers

它等价于这个,flask 还是给返回了response对象。

解决核心对象重复引用

在flask中,将app的核心对象和注册路由写在同一个文件中是非常不好的体验

from flask import Flask
app = Flask(__name__)

@app.route('/hello')
def hello():
	return 'Hello world!'

app.run(debug=True)

只有1,2个路由是没问题的,可是,当有上百个路由的时候,而且开发者10个人同时在开发,大家都修改这一个入口文件,会造成很差的体验。
所以我们需要可以拆分路由,那么如何才能拆分呢?
可以add_url 的方式手动注册,但这种并不优雅。
我认为有两种比较好的
在这里插入图片描述
方式1: 保持核心对象app 只有一个,在util_help.py中定义一个函数,

from flask import Flask
def my_function():
    # 定义静态变量
    if not hasattr(my_function, "my_static_variable"):
        my_function.my_static_variable = Flask(__name__)
    
    return my_function.my_static_variable

谁用到app对象都去这里满拿,因为是定义了静态变量,所以,是独一份的,不会随着包引用构建多次. 注册路由是没问题的.

方式2: 通常情况会出现循环引用,因为入口文件会引入 app.web.book 文件, 而book文件又会去入口文件引入app, 造成两个app, 在book文件中的app对象,注册了路由函数,但不是入口文件的app对象.这个时候,蓝图就起作用了.

Flask的经典错误

working outside application context
AppContext, RequestContext, Flask与Request直接的关系.
应用上下文 对象 Flask
请求上下文 对象 Request
Flask AppContext
Request RequestContext
在这里插入图片描述
在这里插入图片描述
做上下文管理的源码!
用这两句把current_app 推进占
在这里插入图片描述
上下文管理的逻辑使用场景:
数据库:
1.连接数据库
2.执行sql
3.释放资源
解决方法1:
try

except

finall

解决方法2:
with 语句, 可以对比 whith open() as f:

文件读写:

try: 
	f = open(r"D:/t.txt")
	print(f.read())
finally:
	f.close()
with open(r"D:/t.txt") as f:
	print(f.read())

只要实现了__enter__ 和 __exit__方法就是上下文管理器.

class A:
	def __enter__(self):
	    a = 1
	def __exit__(self,exc_type, exc_value, tb):	
		if tb:
			print("process exception")
		else:
			print('no exception')
		b = 2
		return True
		# 或者返回 False, 代表异常还需要接着抛出去,
		# True 异常里面出来,外面不抛出异常
		# 什么都不返回 和False 的逻辑一致
		

with A() as obj_A:
     pass

现在的 obj_A 是 None
as 返回的不是上下文管理器,而是 enter方法返回的值.

with 语句包裹的变量值是有值的, 运行exit之后,就没值了.因为分别执行了 push 和pop,
push 就是把变量放进去, pop 就弹出来了.

flask的多线程和线程隔离

资源是稀缺的,计算机资源 竞争计算机资源
进程 至少由1个进程, 进程是竞争计算机的基本单位

单核cpu, 永远只能执行一个应用程序?
再不同的应用程序之间切换

进程调度 切换到另外一个进程 操作系统原理
进程/线程 开销是非常大 上下文
线程是进程的一部分 1个线程 多个线程
cpu 颗粒度太大了 更小的单元 cpu的资源
线程

进程 分配资源 内存资源
线程 利用cpu执行代码

代码 指令 cpu来执行 原料
线程不能够拥有资源,但 线程属于进程,可以访问进程资源

主线程


def worker():
	print("i am thread")
	t = threading.current_thread()
	print(t.get.getName())
import threading
print("i  am  7 月")
t = threading.current_thread()
print(t.getName())

new_t = threading.Thread(target=work)

在这里插入图片描述
线程名字可以改变。
多线程是为了更加充分的利用cpu的性能优势。
异步变成
单核cpu
4核心 A核 B核 并行的执行顺序
python不能充分利用多核cpu的优势,这句话是对的。因为python有GIL 全局解释器锁 global interpreter lock

python的多线程是鸡肋? 不是的。IO密集的是有用的。

锁 是为了负责线程安全
细小粒度的锁, 解释器 GIL 多核cpu 1个线程执行,一定程度上保证线程安全
a+=1
bytecode

python 多线程到底是不是鸡肋

python 有GIL, 是在字节码bytecode基础上的单线程。
node,js 是单进程单线程的。
CPU密集型的程序,多线程就是垃圾,鸡肋
IO密集型的程序,查询数据库,请求网络资源,读写文件。那么python的多线程是有意义的。

flask web框架 和客户端请求的关系

框架代码/webserver/自己写的代码 要区分开
Java PHP nginx Apache Tomcat IIS
app.run 是启动了一个flask 内置的webserver
真实环境下,不用flask自带的,因为默认情况下它是单进程单线程的形式提供服务的。在开发阶段是可以的,方便调试,真正部署的时候不用它。实际上,flask 自带的服务器也可以开启自带的多线程模型, 可以开启单线程多进程, 也可以开启多进程,多线程模型。

app.run(host='0.0.0.0', debug=True, port=81,threaded=True,)

process默认是1,也可以开启多进程,也是一个参数。

对于一个接口,实际请求不同,如何保证返回的结果是隔离的。

比如用户a, 是访问 作者是金庸 page=1的书目列表。。用户b是另外一个。
那么,实例化的request请求信息是如何隔离的?
在单线程下是排队的,没问题。但是多线程下如何做到的呢?
答案: 线程隔离技术
在这里插入图片描述
一个变量名,指向了多个实例化的Request,这个问题如何解决。

import threading
request = None
request1 = Request()
request2 = Request()
request3 = Request()

## python 字典 php 数组
request = {
	key1:v1
	k2:v2
	k3:v3
}

所以用线程的标识 作为key,文件就解决了。
request = {
	thread_key1:v1
	thread_key2:v2
	thread_key3:v3
}

用字典这种基本的数据结构,来完成线程隔离。
flask是借助werkzeug 下面的local模块的Local对象来完成的。
local对象的本质就是用字典的方式来解决的。
追一下源码:
在这里插入图片描述

取当前线程的id号
在这里插入图片描述
Local对象
在这里插入图片描述

如何在当前线程,通过线程id号,拿到线程的值?
L 线程隔离的对象
t1 L.a 和 t2 L.a 是完全隔离的,互不干扰
这个Local对象不一定非要在flask下使用,还可以自己使用.



class A:
	b = 1

my_obj = Local()

def worker():
	#新线程
	my_obj.b = 2


new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
from werkzeug.local import Local


my_obj = Local()
my_obj.b = 1
def worker():
	#新线程
	my_obj.b = 2
	print("in new thread b is :"+ str(my_obj.b))


new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
print("in main thread b is :"+ str(my_obj.b))

Local, LocalStack 和字典的关系

在这里插入图片描述

LocalStack的核心方法 push/pop和top,继承自 localStack的核心属性local就是Local()的对象.
在这里插入图片描述

在这里插入图片描述
Local使用字典的方式实现现场隔离,localstack是线程隔离的栈结构.

LocalStack的基础用法

以下讲解体现了LocalStack 作为stack的特性的用法.

from werkzeug.local import LocalStack
# 重点是要实现push, pop和top
s = LocalStack()
s.push(1)
s.top  # 读取栈顶元素,但不会删除, 需要注意点是,以属性的形式读取的,不需要加括号
s.pop() # 获取并且弹出栈顶

在这里插入图片描述
而且栈是后进先出.

以下讲解体现了LocalStack 作为Local的特性的用法.
在这里插入图片描述

from werkzeug.local import LocalStack

my_stack = LocalStack()
my_Stack.push(1)
print("in main thread after push, value is:"+ str(my_stack.pop))
def worker():
	# 新线程
	print("in main thread after push, value is:"+ str(my_stack.pop))
	my_Stack.push(2)
	print("in main thread after push, value is:"+ str(my_stack.pop))

new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
print("in main thread b is :"+ str(my_Stack.top))

打印结果:
在这里插入图片描述
之前知道localstack的这个特性就好了,当时手写多进程那么辛苦~~~~解决 显卡不足的问题.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/479433.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM整合(三) | 异常处理器 - 项目异常的处理方案

文章目录 异常处理器异常处理器快速入门项目异常处理 异常处理器 异常处理器快速入门 程序开发过程中不可避免的会遇到异常现象 出现异常现象的常见位置与常见原因如下&#xff1a; 框架内部抛出的异常&#xff1a;因使用不规范导致 数据层抛出的异常&#xff1a;因外部服务器…

使用Statsmodel进行假设检验和线性回归

如果你使用 Python 处理数据&#xff0c;你可能听说过 statsmodel 库。Statsmodels 是一个 Python 模块&#xff0c;它提供各种统计模型和函数来探索、分析和可视化数据。该库广泛用于学术研究、金融和数据科学。在本文中&#xff0c;我们将介绍 statsmodel 库的基础知识、如何…

【技巧】Excel序号设置自动更新

做Excel表格的时候&#xff0c;我们经常需要设置序号&#xff0c;在输入序号的时候&#xff0c;你是不是这样做&#xff1f;手动输入序号1&#xff0c;再向下填充&#xff0c;当遇到有不想要的内容&#xff0c;点删除后&#xff0c;发现中间的序号就不连贯了&#xff0c;再手动…

二十五、OSPF高级技术——开销值、虚链路、邻居建立、LSA、多进程

文章目录 调试指令&#xff08;三张表&#xff09;1、邻居表&#xff1a;dis ospf peer brief2、拓扑表&#xff08;链路状态数据库&#xff09;&#xff1a;dis ospf lsdb3、路由表&#xff1a;dis ip routing-table 一、OSPF 开销值/度量值&#xff08;cost&#xff09;1、co…

代码审计笔记之开篇

思想 代码审计是从软件测试发展而来&#xff0c;早起一般采用常规软件测试与渗透测试的手段来发现源码漏洞&#xff0c;但是随着软件规模的越来越大&#xff0c;架构越来越复杂&#xff0c;安全漏洞和后门也越来越多越来越隐蔽&#xff0c;这使得传统的软件测试方法很难检出源…

【Java入门合集】第二章Java语言基础(一)

【Java入门合集】第二章Java语言基础&#xff08;一&#xff09; 博主&#xff1a;命运之光 专栏JAVA入门 学习目标 掌握变量、常量、表达式的概念&#xff0c;数据类型及变量的定义方法&#xff1b; 掌握常用运算符的使用&#xff1b; 掌握程序的顺序结构、选择结构和循环结构…

C/C++每日一练(20230501)

目录 1. 对链表进行插入排序 &#x1f31f;&#x1f31f; 2. 找出小于平均值的数 ※ 3. 二叉树的最大深度 &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 对链表进行…

【五一创作】Apollo(入门)

Apollo(入门) Quick Start 配置中心是一种统一管理各种应用配置的基础服务组件 Apollo&#xff08;阿波罗&#xff09;是携程框架部门研发的分布式配置中心&#xff0c;能够集中化管理应用不同环境、不同集群的配置&#xff0c;配置修改后能够实时推送到应用端&#xff0c;并且…

Springboot 实战一个依赖解决XSS攻击

1. 什么是XSS介绍 XSS: Cross Site Scripting&#xff0c;为不和层叠样式表(Cascading Style Sheets, CSS) 的缩写混淆&#xff0c;故将跨站脚本攻击缩写为XSS。 恶意攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中 Web里面的Scrip…

【高并发】并发数据结构与多核编程

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于多处理器编程的艺术进行的&#xff0c;每个知识点的修正和深入主要…

【JavaEE初阶】认识线程(Thread)

目录 &#x1f33e; 前言 &#x1f33e; 了解线程 &#x1f308;1.1 线程是什么&#xff1f; &#x1f308;1.2 一些基本问题 &#x1f33e;2、创建线程的方式 &#x1f308; 2.1 继承Thread类 &#x1f308; 2.2 实现Runnable接口并重写run()方法 &#x1f308; 注意…

有哪些好的学习方法?学霸们自己在用,却不愿意透露的

临近期末,很多家长都在跟我咨询,怎么才能提升孩子的学习效率? 原因就是,每天看着自己的孩子学习到深夜,但不少内容还是记不住, 学习和复习的效果非常的不理想。 今天,给大家分享的方法,是我自己一直也都在用的方法,效果非常的棒。 学长Ron,江苏某省重点高中毕业,高…

给公司搭建一个人才库系统,前台(信息填写+简历上传)后台(筛选功能+下载简历)

首先指出目前代码的不足之处&#xff1a; 如果公司使用&#xff0c;代码还存在风险问题&#xff0c;需要增加防火墙、防PHP攻击、后台加验证等操作 以下指南&#xff1a; 1.Mod Security 和 Fail2Ban 是开源的安全软件&#xff0c;您可以在宝塔面板上安装和配置这些软件来增强您…

【JUC】ThreadLocal

【JUC】ThreadLocal 文章目录 【JUC】ThreadLocal1. 概述2. Thread、ThreadLocal、ThreadLocalMap 关系2.1 Thread 和 ThreadLocal2.2 ThreadLocal 和 ThreadLocalMap2.3 三者之间的关系 1. 概述 ThreadLocal 提供线程局部变量。这些变量与正常的变量不同&#xff0c;因为每一…

Java 基础入门篇(一)—— Java 概述

文章目录 一、Java 概述二、Java 的产品 JDK2.1 JDK 安装2.2 Java与 Javac 介绍2.3 Java 程序的开发步骤 三、Java 程序的执行原理四、JDK 的组成五、Java 的跨平台工作原理 一、Java 概述 Java 是 sun 公司在 1995 年推出的一门计算机高级编程语言&#xff0c;其语言风格接近人…

音视频技术开发周刊 | 291

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 谷歌将 AI 芯片团队并入云计算部门 追赶微软和亚马逊 OpenAI推出的ChatGPT获得一定成功&#xff0c;微软是OpenAI的重要投资者&#xff0c;它将ChatGPT植入必应搜索&#…

Java 基础入门篇(三)—— 数组的定义与内存分配

文章目录 一、数组的定义1.1 静态初始化数组1.2 动态初始化数组1.3 数组的访问 二、数组的遍历三、数组的内存图 ★3.1 Java 的内存分配3.2 数组的内存图3.3 两个数组变量指向同一个数组对象 四、数组使用的常见问题补充&#xff1a;随机数 Random 类 一、数组的定义 数组就是…

机器视觉工程师职场四点“心态>交流=思路>知行合一”

视觉人机器视觉团队,他们热爱机器视觉行业,爱学习,爱分享。这一路上,首先感谢粉丝们805天一如既往的支持。我想团队拥有这些粉丝,是富有的,也是我们一直创作的动力。 是否记得毕业季,自己的豪言壮语。希望你毕业三年后,无论结果如何,不忘初心,继续前行。 机器视觉工程…

Dart - 爬取Android Studio历史版本信息

文章目录 前言开发环境开发过程1. 遵循robots协议2. 页面结构分析3. Dart项目创建4. Dart项目运行与调试5. 第三库依赖6. 项目完整源码 运行结果最后 前言 整理Android Studio历史版本信息时发现有点多&#xff0c;于是想一劳永逸写一个简单的爬虫抓取一下数据并生成我想要的格…

【ansys】网格划分-优化、改善网格质量、修复网格、减小skewness、增大Orthogonal Quality的技巧

一、分析几何结构网格划分拓扑关系&#xff0c;调整网格尺寸 优化策略1&#xff1a;如果发现质量差的网格单元聚集在某一个实体附近&#xff0c;基本说明是这个实体的网格划分定义存在优化的地方。 例如下面这个几何模型。一个薄壁状长方体&#xff0c;加上一个模具框架&#x…