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