ES6-變數解構賦值啦
更多python教程請到: 菜鳥教程www.piaodoo.com
人人影視www.sfkyty.com
假設有這樣一個需求,你需要從 Redis 中持續不斷讀取資料,並把這些資料寫入到 MongoDB 中。你可能會這樣寫程式碼:
import json import redis import pymongo client = redis.Redis() handler = pymongo.MongoClient().example.col while True: data_raw = client.blpop('data', timeout=300) if not data_raw: continue data = json.loads(data_raw[1].decode()) handler.insert_one(data)
但這樣寫有一個問題,就是每來一條資料都要連線一次 MongoDB,大量時間浪費在了網路 I/O上。
於是大家會把程式碼改成下面這樣:
import json import redis import pymongo client = redis.Redis() handler = pymongo.MongoClient().example.col to_be_insert = [] while True: data_raw = client.blpop('data', timeout=300) if not data_raw: continue data = json.loads(data_raw[1].decode()) to_be_insert.append(data) if len(to_be_insert) >= 1000: handler.insert_many(to_be_insert) to_be_insert = []
每湊夠1000條資料,批量寫入到 MongoDB 中。
現在又面臨另外一個問題。假設因為某種原因,我需要更新這個程式,於是我按下了鍵盤上的Ctrl + C強制關閉了這個程式。而此時to_be_insert列表裡面有999條資料將會永久丟失——它們已經被從 Redis 中刪除了,但又沒有來得及寫入 MongoDB 中。
我想實現,當我按下 Ctrl + C 時,程式不再從 Redis 中讀取資料,但會先把to_be_insert中的資料(無論有幾條)都插入 MongoDB 中。最後再關閉程式。
要實現這個需求,就必須在我們按下Ctrl + C時,程式還能繼續執行一段程式碼。可問題是按下Ctrl + C時,程式就直接結束了,如何還能再執行一段程式碼?
實際上,當我們按下鍵盤上的Ctrl + C時,Python 收到一個名為SIGINT的訊號。具體規則可以閱讀官方文件。收到訊號以後,Python 會呼叫一個訊號回撥函式。只不過預設的回撥函式就是讓程式丟擲一個 KeyboardInterrupt異常導致程式關閉。現在,我們可以設法讓 Python 使用我們自定義的一段函式來作為訊號回撥函式。
要使用訊號,我們需用匯入 Python 的signal庫。然後自定義一個訊號回撥函式,當 Python 收到某個訊號時,呼叫這個函式。
所以我們修改一下上面的程式碼:
import signal import json import redis import pymongoclient = redis.Redis()
handler = pymongo.MongoClient().example.col
stop = Falsedef keyboard_handler(signum, frame):
global stop
stop = Truesignal.signal(signal.SIGINT, keyboard_handler)
to_be_insert = []
while not stop:
data_raw = client.blpop('data', timeout=300)
if not data_raw:
continue
data = json.loads(data_raw[1].decode())
to_be_insert.append(data)
if len(to_be_insert) >= 1000:
handler.insert_many(to_be_insert)
to_be_insert = []if to_be_insert:
handler.insert_many(to_be_insert)
我們定義了一個全域性變數stop,預設為 False,所以預設情況下,while not stop所在的迴圈體會持續執行。
我們定義了一個函式keyboard_handler,它的作用是修改全域性變數stop為 True。需要注意的是,在函式裡面修改全域性變數,必須先使用global 變數名宣告這個變數為全域性變數。否則無法修改。
修改以後,while not stop迴圈停止,於是程式進入:
if to_be_insert: handler.insert_many(to_be_insert)
只要列表裡面有資料,就會批量插入 MongoDB 中。然後程式結束。
整段程式碼的關鍵就在signal.signal(signal.SIGINT, keyboard_handler)這裡把訊號SIGINT與函式keyboard_handler關聯上了,於是,在上面這段程式碼執行的任何時候,只要按下鍵盤的Ctrl + C,程式就會進入keyboard_handler函式裡面,優先執行這個函式裡面的程式碼。執行完成以後,回到之前中斷的地方,繼續執行之前沒有完成的程式碼。而由於在函式裡面我已經修改了stop的值,所以原來的迴圈不能繼續執行,於是進入最後的收尾工作。
需要注意的是,如果你的整個程式碼全都是使用 Python 寫的,那麼 signal可以在你程式的任何階段觸發,只要你按下 Ctrl + C,立刻就會進入設定好的訊號回撥函式中。
但如果你的程式碼中,有一部分程式碼是使用 C 語言寫的,那麼當你按下Ctrl + C以後,可能需要等這段C 語言的程式碼執行完成以後,才會進入你設定的訊號回撥函式中。
總結
以上所述是小編給大家介紹的在 Python 中接管鍵盤中斷訊號的處理方法,希望對大家有所幫助!