1.DBUtils(pymysql数据连接池)
import pymysql from DBUtils.PooledDB import PooledDB POOL = PooledDB( creator=pymysql, # 使用链接数据库的模块 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服务端,检查是否服务可用。 # 如:0 = None = never, # 1 = default = whenever it is requested, # 2 = when a cursor is created, # 4 = when a query is executed, # 7 = always host='127.0.0.1', port=3306, user='root', password='wcy123', database='flask', charset='utf8' ) sql = "select * from student" def get_conn(): conn = POOL.connection() cursor = conn.cursor(pymysql.cursors.DictCursor) return conn, cursor def reset_conn(conn, cursor): conn.close() cursor.close() def fetch_all(sql, *args): conn, cursor = get_conn() cursor.execute(sql, args) ret_ = cursor.fetchall() reset_conn(conn, cursor) return ret_ def fetch_one(sql, *args): conn, cursor = get_conn() cursor.execute(sql, args) ret_ = cursor.fetchone() reset_conn(conn, cursor) return ret_ ret1 = fetch_all(sql, ) print(ret1) ret2 = fetch_one(sql, ) print(ret2)
2.request管理上下文分析
1) 简单werkzeug服务启动:
from werkzeug.serving import run_simple from werkzeug.wrappers import Request, Response @Request.application def app(request): print(request.method) return Response("200 ok") run_simple("127.0.0.1", 9527, application=app)
2) from threading import local
Python: threading.local是全局变量但是它的值却在当前调用它的线程当中 在threading module中,有一个非常特别的类local。一旦在主线程实例化了一个local,它会一直活在主线程中,并且又主线程启动的子线程调用这个local实例时,它的值将会保存在相应的子线程的字典中。 我们先看看测试代码: #!/usr/bin/python # -*- coding: utf-8 -*- # Description: test the threading.local class # Create: 2008-6-4 # Author: MK2[fengmk2@gmail.com] from threading import local, enumerate, Thread, currentThread local_data = local() local_data.name = 'local_data' class TestThread(Thread): def run(self): print currentThread() print local_data.__dict__ local_data.name = self.getName() local_data.add_by_sub_thread = self.getName() print local_data.__dict__ if __name__ == '__main__': print currentThread() print local_data.__dict__ t1 = TestThread() t1.start() t1.join() t2 = TestThread() t2.start() t2.join() print currentThread() print local_data.__dict__ 运行结果: <_MainThread(MainThread, started)> {'name': 'local_data'} <TestThread(Thread-1, started)> {} {'add_by_sub_thread': 'Thread-1', 'name': 'Thread-1'} <TestThread(Thread-2, started)> {} {'add_by_sub_thread': 'Thread-2', 'name': 'Thread-2'} <_MainThread(MainThread, started)> {'name': 'local_data'} 主线程中的local_data并没有被改变,而子线程中的local_data各自都不相同。 怎么这么神奇?local_data具有全局访问权,主线程,子线程都能访问它,但是它的值却是各当前线程有关,究竟什么奥秘在这里呢? 查看了一下local的源代码,发现就神奇在_path()方法中: def _patch(self): key = object.__getattribute__(self, '_local__key') d = currentThread().__dict__.get(key) if d is None: d = {} currentThread().__dict__[key] = d object.__setattr__(self, '__dict__', d) # we have a new instance dict, so call out __init__ if we have # one cls = type(self) if cls.__init__ is not object.__init__: args, kw = object.__getattribute__(self, '_local__args') cls.__init__(self, *args, **kw) else: object.__setattr__(self, '__dict__', d) 每次调用local实例的属性前,local都会调用这个方法,找到它保存值的地方. d = currentThread().__dict__.get(key) 就是这个地方,确定了local_data值的保存位置。所以子线程访问local_data时,并不是获取主线程的local_data的值,在子线程第一次访问它是,它是一个空白的字典对象,所以local_data.__dict__为 {},就像我们的输出结果一样。 如果想在当前线程保存一个全局值,并且各自线程互不干扰,使用local类吧。
3)
4) 什么时候执行的app.__call__函数,怎么把WSGIRequestHandler初始化传进入的从socket接收的内容request传给app处理函数的?
1.什么时候执行的app.__call__函数 run_simple(host, port, self, **options)中 通过inner()函数: srv = make_server(hostname, port, application, threaded, processes, request_handler, passthrough_errors, ssl_context, fd=fd) # srv为BaseWSGIServer实例: BaseWSGIServer(host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd) request_handler 处理函数为WSGIRequestHandler WSGIRequestHandler处理函数通过: 1、BaseWSGIServer的__init__, 2、HTTPServer.__init__(self, get_sockaddr(host, int(port), self.address_family), handler) 3、TCPServer的__init__, 4、传给BaseServer的self.RequestHandlerClass = RequestHandlerClass srv.serve_forever() 继承关系:BaseWSGIServer-》HTTPServer-》TCPServer-》BaseServer : def serve_forever(self, poll_interval=0.5): self._handle_request_noblock() def _handle_request_noblock(self): self.process_request(request, client_address) def process_request(self, request, client_address): self.finish_request(request, client_address) def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # 处理函数实例化,就是WSGIRequestHandler实例化 初始化会执行self.handle()方法: WSGIRequestHandler-》BaseHTTPRequestHandler-》StreamRequestHandler-》BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() WSGIRequestHandler:def handle(self): rv = BaseHTTPRequestHandler.handle(self) def handle(self): self.handle_one_request() def handle_one_request(self): return self.run_wsgi() execute(self.server.app) def execute(app): application_iter = app(environ, start_response) 2. 怎么把WSGIRequestHandler初始化传进入的从socket接收的内容request传给app处理函数的? WSGIRequestHandler的祖辈类StreamRequestHandler, 在setup函数中将request处理后传给self.rfile def setup(self): self.connection = self.request if self.timeout is not None: self.connection.settimeout(self.timeout) if self.disable_nagle_algorithm: self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) self.rfile = self.connection.makefile('rb', self.rbufsize) if self.wbufsize == 0: self.wfile = _SocketWriter(self.connection) else: self.wfile = self.connection.makefile('wb', self.wbufsize) 在WSGIRequestHandler中将self.rfile传给environ: environ = { 'wsgi.version': (1, 0), 'wsgi.url_scheme': url_scheme, 'wsgi.input': self.rfile, 'wsgi.errors': sys.stderr, 'wsgi.multithread': self.server.multithread, 'wsgi.multiprocess': self.server.multiprocess, 'wsgi.run_once': False, 'werkzeug.server.shutdown': shutdown_server, 'SERVER_SOFTWARE': self.server_version, 'REQUEST_METHOD': self.command, 'SCRIPT_NAME': '', 'PATH_INFO': wsgi_encoding_dance(path_info), 'QUERY_STRING': wsgi_encoding_dance(request_url.query), 'REMOTE_ADDR': self.address_string(), 'REMOTE_PORT': self.port_integer(), 'SERVER_NAME': self.server.server_address[0], 'SERVER_PORT': str(self.server.server_address[1]), 'SERVER_PROTOCOL': self.request_version } 通过application_iter = app(environ, start_response)传给app,在通过app传给request实例化: request = app.request_class(environ)
5)简要流程:
问题一:flask和django的区别: 对于django来说,内部组件特别多,自身功能强大,有点大而全,而flask,内置组件很少,但是它的第三方组件很多,扩展性强,有点短小精悍,而它们之间也有相似之处, 因为它们两个框架都没有写sockte,都是基于wsgi协议做的,在此之外,flask框架中的上下文管理较为耀眼。 相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的 请求相关数据传递的方式不同:django:通过传递request参数取值 flask:见问题二 组件不同:django组件多 flask组件少,第三方组件丰富 问题1.1: flask上下文管理: 简单来说,falsk上下文管理可以分为三个阶段: 1、请求进来时,将请求相关的数据放入上下问管理中 2、在视图函数中,要去上下文管理中取值 3、请求响应,要将上下文管理中的数据清除 详细点来说: 1、请求刚进来,将request,session封装在RequestContext类中,app,g封装在AppContext类中,并通过LocalStack将requestcontext和appcontext放入Local类中 2、视图函数中,通过localproxy--->偏函数--->localstack--->local取值 3、请求相应时,先执行save.session()再各自执行pop(),将local中的数据清除