浅谈flask的发布订阅
淺談flask的發(fā)布訂閱
發(fā)布-訂閱模式
首先 顧名思義 就像訂閱報(bào)紙一樣,出版社發(fā)布不同類型的報(bào)紙雜志不同的讀者根據(jù)不同的需求預(yù)定符合自己口味的的報(bào)紙雜志,付費(fèi)之后由郵局安排人員統(tǒng)一派送
由上圖可卡因看到三個(gè)比較重要的點(diǎn):
1.發(fā)布者:報(bào)社
2.訂閱者:讀者
3.調(diào)度中心: 郵局
不難看出上述過(guò)程中出版社和讀者完全沒(méi)有任何接觸,在他們沒(méi)有感知到對(duì)方的情況下通過(guò)郵局完成了整個(gè)流程,郵局就是傳說(shuō)中的中介(Broker)
使用發(fā)布-訂閱模式的優(yōu)點(diǎn):
松耦合,可拓展性
Flask - Signals
說(shuō)明
有了前面這個(gè)鋪墊,不難意識(shí)到 Flask 的 Singals 其實(shí)就是我們上面說(shuō)的發(fā)布-訂閱模式的實(shí)現(xiàn).官方文檔對(duì) Signals 的介紹過(guò)于簡(jiǎn)單,容易讓初學(xué)者直接忽略過(guò)去,但是實(shí)際上這知識(shí)點(diǎn)十分重要,尤其在開(kāi)發(fā)比較復(fù)雜的系統(tǒng)中,正確地使用 Singals 能夠幫助我們實(shí)現(xiàn)系統(tǒng)的松耦合.
這種松耦合是通過(guò)某些行為被觸發(fā)時(shí),自動(dòng)發(fā)送定義好的一種信號(hào),與這個(gè)信號(hào)綁定的一些業(yè)務(wù)邏輯或行為,接收到這個(gè)信號(hào)后,會(huì)自動(dòng)執(zhí)行各自相應(yīng)的業(yè)務(wù)邏輯。這些行為的產(chǎn)生者就是我們?cè)诎l(fā)布訂閱模式中發(fā)布者,通過(guò)調(diào)度中心,消息被轉(zhuǎn)發(fā)到相應(yīng)的訂閱者,然后每個(gè)訂閱者執(zhí)行自己的邏輯,互不干擾.
就像我們?cè)诎l(fā)布-訂閱模式看到的那樣,我們可以隨時(shí)添加訂閱者. 同樣地,與該信號(hào)綁定的業(yè)務(wù)邏輯,可以是我們事先預(yù)定義好的,也可以是在后續(xù)開(kāi)發(fā)中隨需求變動(dòng)新增上去的. 在基于 Signals 的機(jī)制下,系統(tǒng)會(huì)更加穩(wěn)定和可擴(kuò)展,也使得系統(tǒng)的業(yè)務(wù)邏輯更加清晰.
例子
Signal 的創(chuàng)建
兩行代碼就可以創(chuàng)建
不過(guò)Flask文檔有另一種寫(xiě)法
from blinker import Namespace my_signals = Namespace() model_saved = my_signals.signal('model-saved')兩者本質(zhì)上是沒(méi)有任何區(qū)別的,原因我們可以看一下 blinker 的源碼
# https://github.com/jek/blinker/blob/master/blinker/base.py signal = Namespace().signal很顯然從源碼看兩者基本上可以等價(jià)起來(lái),前者只是幫助我們簡(jiǎn)化了一個(gè)步驟
Signal 的發(fā)送
signal 創(chuàng)建好了之后,接下來(lái)就是使用了,使用很簡(jiǎn)單通過(guò)調(diào)用 send() 函數(shù).需要注意的是,官方文檔給了一個(gè)建議:
Try to always pick a good sender. If you have a class that is emitting a signal, pass self as sender. If you are emitting a signal from a random function, you can pass current_app._get_current_object() as sender.
也就說(shuō)明我們?cè)趯?shí)際使用過(guò)程中,最好將 send() 函數(shù)的第一個(gè)參數(shù)為 signal 的發(fā)送者
1.在類中發(fā)送者(sender) 為 self
class Model(object):def save(self):model_saved.send(self)1.在函數(shù)中發(fā)送者(sender) 為 current_app._get_current_object()
def save():model_saved.send(current_app._get_current_object())發(fā)送完消息,消息需要有人看,自然需要訂閱者了.
Signal 的訂閱
訂閱指定的 signal 可以通過(guò)使用 connect() 函數(shù),當(dāng)通過(guò) send() 發(fā)送 signal 時(shí),會(huì)自動(dòng)觸發(fā)這些訂閱者,然后執(zhí)行相應(yīng)邏輯,從而完成相應(yīng)的功能. 使用起來(lái)很簡(jiǎn)單,只需要給指定的函數(shù)加上一個(gè) connect_via 或者 connect 的裝飾器就可以了
讓我們執(zhí)行一下然后看一下結(jié)果:
* Serving Flask app "test" (lazy loading)* Environment: productionWARNING: This is a development server. Do not use it in a production deployment.Use a production WSGI server instead.* Debug mode: on* Restarting with stat* Debugger is active!* Debugger PIN: 326-510-904* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) Got a signal sent by <Flask 'test'>,{'data': 3} 127.0.0.1 - - [24/Jun/2019 15:07:31] "GET / HTTP/1.1" 200 -似乎少了依次輸出?別著急,我們修改一下這個(gè)例子,使用 connect
# connect@test.connectdef subscriber(sender,**kwargs):print(f'Got a signal sent by {sender},{kwargs}')再次執(zhí)行看一下結(jié)果
* Serving Flask app "test" (lazy loading)* Environment: productionWARNING: This is a development server. Do not use it in a production deployment.Use a production WSGI server instead.* Debug mode: on* Restarting with stat* Debugger is active!* Debugger PIN: 326-510-904* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) Got a signal sent by <Flask 'test'>,{'data': 3} Got a signal sent by test,{} 127.0.0.1 - - [24/Jun/2019 15:10:43] "GET / HTTP/1.1" 200 -connect_via 和 connect
從上面最后一次輸出,不難發(fā)現(xiàn)輸出兩次了,為什么第一次的時(shí)候只輸出了一次呢? 很顯然這就是 connect_via 和 connect 的區(qū)別,從上面的例子,我們不難看到, connect_via 多了一個(gè)參數(shù),這個(gè)參數(shù)就是 sender,使用 connect 的訂閱方式并不支持訂閱指定的發(fā)布者,如果我們需要訂閱指定的發(fā)布者需要使用 connect_via(sender)
最后
Signals 是個(gè)好東西,大家應(yīng)該學(xué)會(huì)使用它.
總結(jié)
以上是生活随笔為你收集整理的浅谈flask的发布订阅的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ubuntu 左手使用习惯
- 下一篇: 使用R包itol.toolkit制作精美