zoukankan      html  css  js  c++  java
  • python全栈开发day113-DBUtils(pymysql数据连接池)、Request管理上下文分析

    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)
    sqlHelper

    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)
    werkzeug_demo

    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类吧。
    Python: threading.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)
    什么时候执行的app.__call__函数

    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中的数据清除
    简要流程
  • 相关阅读:
    比较两个json数组是否有相同的选项
    使用gulp实现静态资源版本号替换
    Happy Halloween
    前端学习plan
    Python之函数式编程
    秋意浓
    2018给自己个plan,给自己一个小目标
    see goodbye with 2017
    杂记(一)
    The fruit in mid-summer
  • 原文地址:https://www.cnblogs.com/wuchenggong/p/9780265.html
Copyright © 2011-2022 走看看