面试总结1
1 django和flask的区别
django:大而全,包含了很多组件,eg:ORM、form、ModelForm、session。。。
flask:轻量级的可扩展强的框架,有丰富的第三方组件
相同点:
1 都要依赖wsgi
不同点
1 django组件多,flask组件少(默认的)
2 最大的区别就是对于请求的处理不一样。
django-一步一步将请求传递给视图
flask-将请求放置在“某个地方”,以后想要使用就自己去拿即可
2 flask上下文处理机制 (处理请求的) 基本原理
- 服务端如果是单进程单线程,同一时刻服务端只能处理一个请求,客户端来的多,那么就排队等候。
- 服务端如果是单进程多线程,同一时刻服务端可以处理多个请求,客户端来的多,那么就排队等候
问题:请求如何不被拿错?
方法:
处理请求的身份证号。
在保存数据的地方,保证服务端的每个线程只能去自己的一块区域中存取值。
3 如何实现每个线程都在自己的区域中进行存取数据
import threading
import time
data = threading.local()
def task(arg):
# prient(arg, threading.get)_ident()) # 线程号
# 按理说第一个值被第二个值给覆盖掉了,但是是threading.local()对象 读的时候去自己的线程空间去读值 所以不会被覆盖
data.num = arg # 设置
time.sleep(2)
print(data.num) # 读取
for i in range(2):
t = threadiing.Thread(target=task, args=(i,))
t.start()
4 threading.local()的内部实现原理
内部维护了一个字典
data = threading.local() = {
"线程ID1": {
'k1': 123
},
"线程ID2":{
'k1': 123
}
}
from threading import get_ident, Thread
class Local(object):
def __init__(self):
# self._storage={} # 会出现递归的问题
object.__setattr__(self, "_storage", {})
def __setattr__(self, key, value):
ident = get_ident() # 获取当前执行此方法的线程ID
if ident in self._storage:
self._storage["ident"]["key"] = value
self._storage["ident"] = {key: value}
def __getattr__(self, item):
ident = get_ident() # 获取当前执行此方法的线程ID
return self._storage[ident]['item']
obj = Local()
# obj.k1 = 123 # __setarttr__
# obj.k1 # __getattr__
print(obj._storage)
def task():
obj.k1 = 123
for i in range(2):
t = Thread(target=task)
t.start()
print(obj._storage)
比threading.local()更厉害,为每个协程开辟一个空间进行存储
from threading import get_ident, Thread # 线程ID
from greenlet import getcurrent as get_ident # 协程ID
class Local(object):
def __init__(self):
# self._storage={} # 会出现递归的问题
object.__setattr__(self, "_storage", {})
def __setattr__(self, key, value):
ident = get_ident() # 获取当前执行此方法的线程ID
if ident in self._storage:
self._storage["ident"]["key"] = value
self._storage["ident"] = {key: value}
def __getattr__(self, item):
ident = get_ident() # 获取当前执行此方法的线程ID
return self._storage[ident]['item']
obj = Local()
# obj.k1 = 123 # __setarttr__
# obj.k1 # __getattr__
print(obj._storage)
def task():
obj.k1 = 123
for i in range(2):
t = Thread(target=task)
t.start()
print(obj._storage)
注意:greenlet是需要pip install greenlet的,如果有就走这个,没有走线程的!
5 threading.local()和锁是什么关系
无关系
- 锁,多个线程去同时去操作同一份数据的时,为了保证数据安全才加锁,加锁后让多个线程排队执行
- threading.local(),让多个线程自己维护自己的数据
6 简述Flask请求上下文的实现流程
请求上下文的流程
ctx = RequestContext()对象 放两个对象 一个request,一个session
stack = LocalStack()对象 背后有Locak()对象-自己维护-升级版的threading.local()
LocalProxy()对象
请求进来后先交给RequestContext()对象进行数据的加工 封装 request和创建session
将封装好的数据给LocalStack()对象,
将值给了local = Local()对象
{
1211:{
stack: [ctx, ] # LocalStack()对象
}
}
去cookie中获取session的数据,并赋值给ctx.session
到达视图,request.method/session['k1'] = 999!只要这两段代码存在就会去调用LocalProxy()对象。 request = localproxy() session = LocalProxy()
请求结束!把stack中ctx删除!把数据删掉,把session获取到将它加密变为字符串,存到浏览器的cookie中。
应用上下文
app_ctx = AppContext() app = app g = {}
stack = LocalStack()
local = Local()
视图中加current_app.config / g.x = 123123 ! current_app = LocalProxy() g = LocalProxy()
请求结束!把stack中ctx删除!只处理session不处理其他!
7 flask中session处理机制
请求上下文中,请求结束,处理session
8 flask中g 的作用
在一个请求声明中存活的一个变量