zoukankan      html  css  js  c++  java
  • python 里的 redis 连接池的原理

    python设置redis连接池的好处:
    通常情况下,需要连接redis时,会创建一个连接,基于这个连接进行redis操作,操作完成后去释放,
    正常情况下,这是没有问题的,但是并发量较高的情况下,频繁的连接创建和释放对性能会有较高的影响,于是连接池发挥作用。 连接池的原理:‘预先创建多个连接,当进行redis操作时,直接获取已经创建好的连接进行操作。完成后,不会释放这个连接,
    而是让其返回连接池,用于后续redis操作!这样避免连续创建和释放,从而提高了性能!
    import redis
    pool = redis.ConnectionPool(host='127.0.0.1',port=6379,password='12345')
    r = redis.Redis(connection_pool=pool)
    r.set('name','michael')
    print(r.get('name'))
    

      

    pool = redis.ConnectionPool(host='127.0.0.1',port=6379,password='12345')
    
    直接点击connectionPool,进去查看源码:
    
    
     def __init__(self, connection_class=Connection, max_connections=None,
                     **connection_kwargs):
           
            max_connections = max_connections or 2 ** 31
            if not isinstance(max_connections, (int, long)) or max_connections < 0:
                raise ValueError('"max_connections" must be a positive integer')
    
            self.connection_class = connection_class
            self.connection_kwargs = connection_kwargs
            self.max_connections = max_connections
    
            self.reset()
    
    发现里面只是  设置最大的连接数,连接参数,连接的类,在实例化的时候,并没有做真实的redis连接。
    

      

    r = redis.Redis(connection_pool=pool)
    点击Redis,查看内部的源码:
    在Redis实例化的时候,做了什么;
    def __init__(self, ...connection_pool=None...):
            if not connection_pool:
                ...
                connection_pool = ConnectionPool(**kwargs)
            self.connection_pool = connection_pool
    以上只保留了部分代码:
    可见:使用Redis即使不创建连接池,也会自己创建
    到这,发现还没有实际的redis真实连接
    r.set('name','michael')
    
    点击set,查看内部源码:
    
    def set(self, name, value, ex=None, px=None, nx=False, xx=False):
        ...
        return self.execute_command('SET', *pieces)
    
    
    在此处发现了方法,execute_command,点击进去查看
    
        def execute_command(self, *args, **options):
            "Execute a command and return a parsed response"
            pool = self.connection_pool
            command_name = args[0]
            conn = self.connection or pool.get_connection(command_name, **options)
            try:
                conn.send_command(*args)
                return self.parse_response(conn, command_name, **options)
            except (ConnectionError, TimeoutError) as e:
                conn.disconnect()
                if not (conn.retry_on_timeout and isinstance(e, TimeoutError)):
                    raise
                conn.send_command(*args)
                return self.parse_response(conn, command_name, **options)
            finally:
                if not self.connection:
                    pool.release(conn)
    
    
    找到了conn = self.connection or pool.get_connection(command_name, **options)
    因为self.connection初始值为False,所以此处调用了方法 get_connection
    
    点击查看get_connection,
    
    
        def get_connection(self, command_name, *keys, **options):
            "Get a connection from the pool"
            self._checkpid()
            try:
                connection = self._available_connections.pop()
            except IndexError:
                connection = self.make_connection()
            self._in_use_connections.add(connection)
             。。。。。。
           
            except:  # noqa: E722
    
                self.release(connection)
                raise
    
            return connection
    
    如果有有用的连接,获取可用的连接,没有,自己创建一个 make_connection ,点击查看make_connection
    
    
        def make_connection(self):
            "Create a new connection"
            if self._created_connections >= self.max_connections:
                raise ConnectionError("Too many connections")
            self._created_connections += 1
            return self.connection_class(**self.connection_kwargs)
    
    终于,在此处创建了连接!!!
    
    
    在ConnectionPool的实例中, 有两个list, 依次是_available_connections, _in_use_connections,
    分别表示可用的连接集合和正在使用的连接集合, 在上面的get_connection中, 我们可以看到获取连接的过程是:
    
    从可用连接集合尝试获取连接,
    如果获取不到, 重新创建连接
    将获取到的连接添加到正在使用的连接集合
    
    上面是往_in_use_connections里添加连接的, 这种连接表示正在使用中, 那是什么时候将正在使用的连接放回到可用连接列表中的呢
    
    这个还是在execute_command里, 我们可以看到在执行redis操作时, 在finally部分, 会执行一下
    
    pool.release(connection)
    连接池对象调用release方法, 将连接从_in_use_connections 放回 _available_connections, 这样后续的连接获取就能再次使用这个连接了
    
    release 方法如下
    
     def release(self, connection):
            "Releases the connection back to the pool"
            self._checkpid()
            if connection.pid != self.pid:
                return
            self._in_use_connections.remove(connection)
            self._available_connections.append(connection)
    
    
    至此, 我们把连接池的管理流程走了一遍, ConnectionPool通过管理可用连接列表(_available_connections) 和 正在使用的连接列表从而实现连接池管理!
  • 相关阅读:
    SQL注入攻击
    新手指引,php什么是常量、变量、数组、类和对象及方法?
    JQuery坑,说说哪些大家都踩过的坑
    利用Jsonp实现跨域请求,spring MVC+JQuery
    【实用】需要收藏备用的JQuery代码片段
    【动画】JQuery实现冒泡排序算法动画演示
    【基础】26个命令玩转linux,菜鸟及面试必备
    【收藏】8段JQuery处理表单的代码片段,很实用
    【实用】Html5实现文件异步上传
    【基础】新手任务,五分钟全面掌握JQuery选择器
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/11382035.html
Copyright © 2011-2022 走看看