python redis之連接池的原理
?
轉(zhuǎn)載地址
什么是連接池
通常情況下, 當(dāng)我們需要做redis操作時(shí), 會(huì)創(chuàng)建一個(gè)連接, 并基于這個(gè)連接進(jìn)行redis操作, 操作完成后, 釋放連接,
一般情況下, 這是沒(méi)問(wèn)題的, 但當(dāng)并發(fā)量比較高的時(shí)候, 頻繁的連接創(chuàng)建和釋放對(duì)性能會(huì)有較高的影響
于是, 連接池就發(fā)揮作用了
連接池的原理是, 通過(guò)預(yù)先創(chuàng)建多個(gè)連接, 當(dāng)進(jìn)行redis操作時(shí), 直接獲取已經(jīng)創(chuàng)建的連接進(jìn)行操作, 而且操作完成后, 不會(huì)釋放, 用于后續(xù)的其他redis操作
這樣就達(dá)到了避免頻繁的redis連接創(chuàng)建和釋放的目的, 從而提高性能了
?
原理
那么, 在redis-py中, 他是怎么進(jìn)行連接池管理的呢
連接池使用
首先看下如何進(jìn)行連接池操作的
rdp = redis.ConnectionPool(host= ' 127.0.0.1 ' , port=6379, password= ' xxxxx ' ) rdc = redis.StrictRedis(connection_pool= rdp) rdc.set( ' name ' , ' Yi_Zhi_Yu ' ) rdc.get( ' name ' )
原理解析
當(dāng)redis.ConnectionPool 實(shí)例化的時(shí)候, 做了什么
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
這個(gè)連接池的實(shí)例化其實(shí)未做任何真實(shí)的redis連接, 僅僅是設(shè)置最大連接數(shù), 連接參數(shù)和連接類
StrictRedis 實(shí)例化的時(shí)候, 又做了什么
def __init__ (self, ...connection_pool= None...): if not connection_pool: ... connection_pool = ConnectionPool(** kwargs) self.connection_pool = connection_pool
以上僅保留了關(guān)鍵部分代碼
可以看出, 使用StrictRedis 即使不創(chuàng)建連接池, 他也會(huì)自己創(chuàng)建
到這里, 我們還沒(méi)有看到什么redis連接真實(shí)發(fā)生
繼續(xù)
下一步就是
set
?操作了, 很明顯, 這個(gè)時(shí)候一定會(huì)發(fā)生redis連接(要不然怎么set)
def set(self, name, value, ex=None, px=None, nx=False, xx= False): ... return self.execute_command( ' SET ' , *pieces)
我們繼續(xù)看看
execute_command
def execute_command(self, *args, ** options): " Execute a command and return a parsed response " pool = self.connection_pool command_name = args[0] connection = pool.get_connection(command_name, ** options) try : connection.send_command( * args) return self.parse_response(connection, command_name, ** options) except (ConnectionError, TimeoutError) as e: connection.disconnect() if not connection.retry_on_timeout and isinstance(e, TimeoutError): raise connection.send_command( * args) return self.parse_response(connection, command_name, ** options) finally : pool.release(connection)
終于, 在這我們看到到了連接創(chuàng)建
connection = pool.get_connection(command_name, **options)
這里調(diào)用的是
ConnectionPool
的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) return connection
如果有可用的連接, 獲取可用的鏈接, 如果沒(méi)有, 創(chuàng)建一個(gè)
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)
終于, 我們看到了, 在這里創(chuàng)建了連接
在ConnectionPool的實(shí)例中, 有兩個(gè)list, 依次是
_available_connections
,?
_in_use_connections
,
分別表示
可用的連接集合
和
正在使用的連接集合
, 在上面的
get_connection
中, 我們可以看到獲取連接的過(guò)程是
- 從可用連接集合嘗試獲取連接,
- 如果獲取不到, 重新創(chuàng)建連接
- 將獲取到的連接添加到正在使用的連接集合
上面是往
_in_use_connections
里添加連接的, 這種連接表示正在使用中, 那是什么時(shí)候?qū)⒄谑褂玫倪B接放回到可用連接列表中的呢
這個(gè)還是在
execute_command
里, 我們可以看到在執(zhí)行redis操作時(shí), 在
finally
部分, 會(huì)執(zhí)行一下
pool.release(connection)
連接池對(duì)象調(diào)用
release
方法, 將連接從
_in_use_connections
?放回?
_available_connections
, 這樣后續(xù)的連接獲取就能再次使用這個(gè)連接了
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)
總結(jié)
至此, 我們把連接池的管理流程走了一遍, ConnectionPool通過(guò)管理
可用連接列表
(
_available_connections
) 和?
正在使用的連接列表
從而實(shí)現(xiàn)連接池管理
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
