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) 和 正在使用的连接列表从而实现连接池管理!

原文地址:https://www.cnblogs.com/changwenjun-666/p/11382035.html

时间: 2024-10-07 07:43:59

python 里的 redis 连接池的原理的相关文章

python 基础 10.0 nosql 简介--redis 连接池及管道

一. NOSQL 数据库简介 NoSQL 泛指非关系型的数据库.非关系型数据库与关系型数据库的差别 非关系型数据库的优势: 1.性能NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL 层的解析,所以性能非常高. 2.可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展. 关系型数据库的优势: 1. 复杂查询可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询. 2.事务支持使得对于安全性能很高的数据访问要求得以实现.对于这两类数据

day24——NoSQL简介、redis服务搭建、redis连接池、redis管道

一.Redis 安装 yum install -y epel-releaseyum install -y gcc jemalloc-devel wgetcd /usr/local/srcwget https://codeload.github.com/antirez/redis/tar.gz/2.8.21 -O redis-2.8.21.tar.gztar xf redis-2.8.21.tar.gzcd redis-2.8.21makemake PREFIX=/usr/local/redis

redis 连接池 - 转载

所需jar:jedis-2.1.0.jar和commons-pool-1.5.4.jar Jedis操作步骤如下:1->获取Jedis实例需要从JedisPool中获取:2->用完Jedis实例需要返还给JedisPool:3->如果Jedis在使用过程中出错,则也需要还给JedisPool: package com.ljq.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; imp

java中使用jedis操作redis(连接池方式)

1 package com.test; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import java.util.List; 6 import java.util.Map; 7 8 import org.junit.Before; 9 import org.junit.Test; 10 11 import redis.clients.jedis.Jedis; 12 13 public class TestRedis

Java的Redis连接池代码性能不错

其实这个是引用自网友http://blog.csdn.net/tuposky/article/details/45340183,有2个版本,差别就是ReentrantLock和synchronized.另外原作者使用了断言,我觉得这个还是不用为好. ReentrantLock版 import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.lang.StringUtils; import org.apache

三:Redis连接池、JedisPool详解、Redisi分布式

单机模式: 1 package com.ljq.utils; 2 3 import redis.clients.jedis.Jedis; 4 import redis.clients.jedis.JedisPool; 5 import redis.clients.jedis.JedisPoolConfig; 6 7 /** 8 * Redis操作接口 9 * 10 * @author NiceCui 11 * @version 1.0 2017-6-14 上午08:54:14 12 */ 13

Java Redis 连接池 Jedis 工具类

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.io.InputStream; import java.util.Prop

redis连接池 jedis-2.9.0.jar+commons-pool2-2.4.2.jar

java使用Redis连接池  jar包为 jedis-2.9.0.jar+commons-pool2-2.4.2.jar 1 package com.test; 2 3 import redis.clients.jedis.Jedis; 4 import redis.clients.jedis.JedisPool; 5 import redis.clients.jedis.JedisPoolConfig; 6 7 public class RedisUtil { 8 //Redis服务器IP

Redis连接池

package com.lee.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public final class RedisPool { //Redis服务器IP private static String ADDR = "127.0.0.1"; //Redis的端口号 private