内容:node
1.进程线程复习python
2.flask多线程的问题nginx
3.线程隔离web
4.LocalStackapache
5.flask上下文整理编程
6.多app应用flask
1.进程线程复习服务器
(1)进程session
进程是一个具备必定独立功能的程序关于某个数据集合的一次运行活动。它是操做系统动态执行的基本单元,在传统的操做系统中,进程既是基本的分配单元,也是基本的执行单元多线程
简单说进程就是操做系统调度分配资源的单位,每个应用程序至少有一个进程
(2)线程
线程能够说是进程的一部分,能够有一个线程也能够有多个线程
只用进程管理CPU资源,粒度太大了,须要更小的单元来管理,就出现了线程
(3)进程与线程的区别
(4)多线程的好处
(5)其余
对于普通python(GIL)、node.js来讲通常都是单进程单线程的
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, 如今的状况下确定没法作到
解决办法:全局变量改成dict, 每个线程都有对应的本身的key, 并将request做为value存放。falsk的线程隔离技术也是基于相似的原理实现的。
(2)源码
siet-package/werkzeug/local.py 中的Local类:
1 class Local(object): 2 __slots__ = ('__storage__', '__ident_func__') 3 4 def __init__(self): 5 object.__setattr__(self, '__storage__', {}) # __storge__ 实现空的字典 6 object.__setattr__(self, '__ident_func__', get_ident) # get_ident是获取当前线程id号的 函数 7 8 def __iter__(self): 9 return iter(self.__storage__.items()) 10 11 def __call__(self, proxy): 12 """Create a proxy for a name.""" 13 return LocalProxy(self, proxy) 14 15 def __release_local__(self): 16 self.__storage__.pop(self.__ident_func__(), None) 17 18 def __getattr__(self, name): 19 try: 20 return self.__storage__[self.__ident_func__()][name] 21 except KeyError: 22 raise AttributeError(name) 23 24 def __setattr__(self, name, value): 25 ident = self.__ident_func__() # 取当前线程的 线程id号, 26 storage = self.__storage__ # 类自己的字典 27 try: 28 storage[ident][name] = value # 把当前线程id号存起来 29 except KeyError: 30 storage[ident] = {name: value} 31 32 def __delattr__(self, name): 33 try: 34 del self.__storage__[self.__ident_func__()][name] 35 except KeyError: 36 raise AttributeError(name)
Local类用当前线程的id号看成key存储不一样的线程,不一样线程操做该对象时互不影响,Local类就是线程隔离的对象
Local隔离实例:
1 from werkzeug.local import Local 2 import threading, time 3 4 my_obj = Local() 5 my_obj.b = 1 6 7 8 def worker(): 9 my_obj.b = 2 10 print('in sub thread b is:' + str(my_obj.b)) # 2 11 12 13 subthread1 = threading.Thread(target=worker, name='subthread1') 14 subthread1.start() 15 16 time.sleep(1) 17 18 print('my_obj.b is : {}'.format(my_obj.b)) # 1 19
(3)线程隔离的意义
使用线程隔离使当前线程能正确引用到本身建立的对象,而不是引用到其余线程所建立的对象
4.LocalStack
(1)源码
1 class LocalStack(object): 2 def __init__(self): 3 self._local = Local() 4 5 def __release_local__(self): 6 self._local.__release_local__() 7 8 def _get__ident_func__(self): 9 return self._local.__ident_func__ 10 11 def _set__ident_func__(self, value): 12 object.__setattr__(self._local, '__ident_func__', value) 13 __ident_func__ = property(_get__ident_func__, _set__ident_func__) 14 del _get__ident_func__, _set__ident_func__ 15 16 def __call__(self): 17 def _lookup(): 18 rv = self.top 19 if rv is None: 20 raise RuntimeError('object unbound') 21 return rv 22 return LocalProxy(_lookup) 23 24 def push(self, obj): 25 """Pushes a new item to the stack""" 26 rv = getattr(self._local, 'stack', None) 27 if rv is None: 28 self._local.stack = rv = [] 29 rv.append(obj) 30 return rv 31 32 def pop(self): 33 """Removes the topmost item from the stack, will return the 34 old value or `None` if the stack was already empty. 35 """ 36 stack = getattr(self._local, 'stack', None) 37 if stack is None: 38 return None 39 elif len(stack) == 1: 40 release_local(self._local) 41 return stack[-1] 42 else: 43 return stack.pop() 44 45 @property 46 def top(self): 47 """The topmost item on the stack. If the stack is empty, 48 `None` is returned. 49 """ 50 try: 51 return self._local.stack[-1] 52 except (AttributeError, IndexError): 53 return None
(2)LocalStack和Local关系
(3)使用LocalStack
1 from werkzeug.local import LocalStack # 栈 先进后出 2 # LocalStack经常使用方法: push pop top 3 4 5 s = LocalStack() 6 s.push(1) 7 print(s.top) # top只会取出元素不会删除 8 print(s.top) 9 print(s.pop()) # pop取出元素并删除 10 print(s.top) 11 12 s.push(1) 13 s.push(2) 14 print(s.top) 15 print(s.top) 16 print(s.pop()) 17 print(s.top)
1 from werkzeug.local import LocalStack # 栈 先进后出 2 from threading import Thread 3 import time 4 5 my_stack = LocalStack() 6 my_stack.push(1) 7 print("in main thread after push, value is: " + str(my_stack.top)) # 1 8 9 10 def worker(): 11 # 新线程 12 print("in new thread before push, value is: " + str(my_stack.top)) # None 13 my_stack.push(2) 14 print("in new thread after push, value is: " + str(my_stack.top)) # 2 15 16 17 new_t = Thread(target=worker, name="new thread") 18 new_t.start() 19 time.sleep(1) 20 21 # 主线程 22 print("finally, in main thread value is: " + str(my_stack.top)) # 1
5.flask上下文整理
(1)请求上下文
1 from flask import Flask,request,session,g,current_app 2 3 app = Flask(__name__) 4 5 @app.route('/',methods=['GET',"POST"]) 6 def index(): 7 # request是 LocalProxy 的对象 8 print(request) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request 9 request.method # LocalProxy.__getattr__ --> 10 # str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request 11 # getattr(self._get_current_object(), name) --> ctx.request.method 12 13 request.path # ctx.request.path 14 15 print(session) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.session 16 17 18 print(g) # 执行g对象的__str__ 19 return "index" 20 21 22 if __name__ == '__main__': 23 # 1. app.__call__ 24 # 2. app.wsgi_app 25 app.wsgi_app 26 app.request_class 27 app.run()
(2)应用上下文
1 from flask import Flask,request,session 2 3 app = Flask(__name__) 4 5 @app.route('/',methods=['GET',"POST"]) 6 def index(): 7 # request是 LocalProxy 的对象 8 print(request) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request 9 request.method # LocalProxy.__getattr__ --> 10 # str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.request 11 # getattr(self._get_current_object(), name) --> ctx.request.method 12 13 request.path # ctx.request.path 14 15 print(session) # LocalProxy.__str__ --> str(LocalProxy._get_current_object) --> 调用偏函数 --> ctx.session 16 return "index" 17 18 19 if __name__ == '__main__': 20 # 1. app.__call__ 21 # 2. app.wsgi_app 22 app.wsgi_app 23 app.run()
1 from flask import Flask,request,g 2 3 app = Flask(__name__) 4 5 @app.before_request 6 def before(): 7 g.permission_code_list = ['list','add'] 8 9 10 @app.route('/',methods=['GET',"POST"]) 11 def index(): 12 print(g.permission_code_list) 13 return "index" 14 15 16 if __name__ == '__main__': 17 app.run()
(3)请求上下文及应用上下文
1 a. 请求上下文: 2 - request 3 - session 4 5 b. 应用上下文: 6 请求流程: 7 _request_ctx_stack.local = { 8 9 } 10 11 _app_ctx_stack.local = { 12 13 } 14 15 16 1. 请求到来 ,有人来访问 17 # 将请求相关的数据environ封装到了RequestContext对象中 18 # 再讲对象封装到local中(每一个线程/每一个协程独立空间存储) 19 # ctx.app # 当前APP的名称 20 # ctx.request # Request对象(封装请求相关东西) 21 # ctx.session # 空 22 _request_ctx_stack.local = { 23 惟一标识:{ 24 "stack":[ctx, ] 25 }, 26 惟一标识:{ 27 "stack":[ctx, ] 28 }, 29 } 30 31 32 # app_ctx = AppContext对象 33 # app_ctx.app 34 # app_ctx.g 35 36 _app_ctx_stack.local = { 37 惟一标识:{ 38 "stack":[app_ctx, ] 39 }, 40 惟一标识:{ 41 "stack":[app_ctx, ] 42 }, 43 } 44 45 2. 使用 46 from flask import request,session,g,current_app 47 48 print(request,session,g,current_app) 49 50 都会执行相应LocalProxy对象的 __str__ 51 52 current_app = LocalProxy(_find_app) 53 request = LocalProxy(partial(_lookup_req_object, 'request')) 54 session = LocalProxy(partial(_lookup_req_object, 'session')) 55 56 current_app = LocalProxy(_find_app) 57 g = LocalProxy(partial(_lookup_app_object, 'g')) 58 59 3. 终止,所有pop 60 61 问题1:多线程是如何体现? 62 问题2:flask的local中保存数据时,使用列表建立出来的栈。为何用栈? 63 - 若是写web程序,web运行环境;栈中永远保存1条数据(能够不用栈)。 64 - 写脚本获取app信息时,可能存在app上下文嵌套关系。 65 from flask import Flask,current_app,globals,_app_ctx_stack 66 67 app1 = Flask('app01') 68 app1.debug = False # 用户/密码/邮箱 69 # app_ctx = AppContext(self): 70 # app_ctx.app 71 # app_ctx.g 72 73 app2 = Flask('app02') 74 app2.debug = True # 用户/密码/邮箱 75 # app_ctx = AppContext(self): 76 # app_ctx.app 77 # app_ctx.g 78 79 80 81 with app1.app_context():# __enter__方法 -> push -> app_ctx添加到_app_ctx_stack.local 82 # {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438>]}} 83 print(_app_ctx_stack._local.__storage__) 84 print(current_app.config['DEBUG']) 85 86 with app2.app_context(): 87 # {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438> ]}} 88 print(_app_ctx_stack._local.__storage__) 89 print(current_app.config['DEBUG']) 90 91 print(current_app.config['DEBUG'])
6.多app应用
1 from werkzeug.wsgi import DispatcherMiddleware 2 from werkzeug.serving import run_simple 3 from flask import Flask, current_app 4 5 app1 = Flask('app01') 6 app2 = Flask('app02') 7 8 9 @app1.route('/index') 10 def index(): 11 return "app01" 12 13 14 @app2.route('/index2') 15 def index2(): 16 return "app2" 17 18 # http://www.oldboyedu.com/index --> app1 19 # http://www.oldboyedu.com/admin/index2 --> app2 20 app= DispatcherMiddleware(app1, { 21 '/admin': app2, 22 }) 23 24 if __name__ == "__main__": 25 run_simple('localhost', 5000, app)