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) 和 正在使用的連接列表從而實現連接池管理!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM