標籤:

Python Redis事務學習筆記

最近在研究分散式爬蟲,需要用Redis做一些信息統計的工作,其實是為了擴展scrapy原本的StatsCollector。

其中像inc_value有內置的命令可以使用,但是像max_value這樣的,需要先獲取某個Key的值,然後根據值的大小,決定是否設置新的值,是沒有內置的命令可以使用,只能自己用Redis事務去實現,在網上搜索了很多相關的資料,但一直都不是很明白。

大多數的實現都和官方文檔一樣:

>>> with r.pipeline() as pipe:... while 1:... try:... pipe.watch(OUR-SEQUENCE-KEY)... current_value = pipe.get(OUR-SEQUENCE-KEY)... next_value = int(current_value) + 1... pipe.multi()... pipe.set(OUR-SEQUENCE-KEY, next_value)... pipe.execute()... break... except WatchError:... continue

先實例化一個Pipeline對象,然後Watch一個或多個key, 然後獲取值並處理值。然後開啟事務,添加命令,執行事務。

一直不明白為什麼要Watch,為什麼Watch後可以獲取命令的返回值,而不Watch卻無法獲取返回值。反正就是無法理解上述的流程。

今天研究了一下python redis客戶端的源碼,對這個流程感悟很多。

Redis在處理事務的時候,對事務中的每一條命令是不會立即執行,而是會將其放入一個隊列中,當執行EXEC命令是,才會執行隊列中的命令。這樣的話如果我需要在事務中根據某條命令的返回值決定下一步的動作,是無法實現的。Redis給出的解決辦法就是Watch命令。

為什麼Watch命令可以解決呢?

Watch命令是用來監視一個或者多個Key,其實就是為這些Key加了一個樂觀鎖(可以理解為記錄下此時Key的Value以及一些其他的元數據)。然後當執行事務的時候,會首先檢查Watch的Key的狀態是否發生變化,如果發生變化,則這個事務就不會被執行。當執行EXEC, UNWATCH, DISCARD命令後,就是取消監控,即釋放了樂觀鎖。

由於在事務中,無法獲取命令的返回值。但是執行Watch後,可以獲取命令的返回值。這樣當我需要根據某個Key的值,做出判斷時,可以先Watch這個Key,然後獲取這個Key的值。再執行事務。如果在執行事務之前Key的狀態發生改變,就不會執行這個事務了,並且會拋出異常,這樣我們就知道事務沒有被執行成功,一般情況下可以捕獲這個異常,並重新執行,直到整個流程是原子的執行完成。


推薦閱讀:

不再寫 for 循環
superset二次開發之旅 - 集成echart圖表
為什麼在Python中沒有專門的char數據類型呢?
如何用爬蟲下載中國土地市場網的土地成交數據?
Python是一門傑出的語言,值得你去學習

TAG:Redis | Python |