国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Golang事件總線機制的實現

Linux愛好者 ? 來源:wangbjun.site ? 作者:wangbjun.site ? 2022-07-01 16:02 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

【導讀】本文介紹了事件總線實現。

最近在學習開源項目Grafana的代碼,發現作者實現了一個事件總線的機制,在項目里面大量應用,效果也非常好,代碼也比較簡單,介紹給大家看看。

源碼文件地址:grafana/bus.go at main · grafana/grafana · GitHub

1.注冊和調用

在這個項目里面隨處可見這種寫法:

funcValidateOrgAlert(c*models.ReqContext){
id:=c.ParamsInt64(":alertId")

query:=models.GetAlertByIdQuery{Id:id}

iferr:=bus.Dispatch(&query);err!=nil{
c.JsonApiErr(404,"Alertnotfound",nil)
return
}

ifc.OrgId!=query.Result.OrgId{
c.JsonApiErr(403,"Youarenotallowedtoedit/viewalert",nil)
return
}
}

關鍵是bus.Dispatch(&query)這段代碼,它的參數是一個結構體GetAlertByIdQuery,內容如下:

typeGetAlertByIdQuerystruct{
Idint64
Result*Alert
}

根據名字可以看出這個方法就是通過Id去查詢Alert,其中Alert結構體就是結果對象,這里就不貼出來了。

通過查看源碼可以得知,Dispatch背后是調用了GetAlertById這個方法,然后把結果賦值到query參數的Result中返回。

funcGetAlertById(query*models.GetAlertByIdQuery)error{
alert:=models.Alert{}
has,err:=x.ID(query.Id).Get(&alert)
if!has{
returnfmt.Errorf("couldnotfindalert")
}
iferr!=nil{
returnerr
}
query.Result=&alert
returnnil
}

問題來了,這是怎么實現的呢?Dispatch到底做了哪些操作?這樣做有什么好處?

下面我來一一解答:

首先,在Dispatch之前,你需要先注冊這個方法,也就是調用AddHandler,在這個項目里面可以看到init函數里面有大量這樣的代碼:

funcinit(){
bus.AddHandler("sql",SaveAlerts)
bus.AddHandler("sql",HandleAlertsQuery)
bus.AddHandler("sql",GetAlertById)
...
}

其實這個方法的邏輯也很簡單,所謂注冊也就是把通過一個map把函數名和對應的函數做一個映射關系保存起來,當我們Dispatch的時候其實就是通過參數名查找之前注冊過的函數,然后通過反射調用該函數。

Bus結構體里面有幾個map成員,在這個項目里面作者定義了3種不同類型的handler,一種是普通的handler,也就是剛才展示的那種,第二種是帶上下文的handler,還有一種則是事件訂閱用到的handler,我們給一個事件注冊多個監聽者,當事件觸發的時候會依次調用多個監聽函數,其實就是一個觀察者模式。

//InProcBusdefinesthebusstructure
typeInProcBusstruct{
handlersmap[string]HandlerFunc
handlersWithCtxmap[string]HandlerFunc
listenersmap[string][]HandlerFunc
txMngTransactionManager
}

下面就看看具體的源碼,AddHandler方法內容如下:

func(b*InProcBus)AddHandler(handlerHandlerFunc){
handlerType:=reflect.TypeOf(handler)
queryTypeName:=handlerType.In(0).Elem().Name()//獲取函數第一個參數的名稱,在上面例子里面就是GetAlertByIdQuery
b.handlers[queryTypeName]=handler
}

Dispatch方法的源碼如下:

func(b*InProcBus)Dispatch(msgMsg)error{
varmsgName=reflect.TypeOf(msg).Elem().Name()

withCtx:=true
handler:=b.handlersWithCtx[msgName]//根據參數名查找注冊過的函數,先查找帶Ctx的handler
ifhandler==nil{
withCtx=false
handler=b.handlers[msgName]
ifhandler==nil{
returnErrHandlerNotFound
}
}
varparams=[]reflect.Value{}
ifwithCtx{
//如果查找到的handler是帶Ctx的就給個默認的Background的Ctx
params=append(params,reflect.ValueOf(context.Background()))
}
params=append(params,reflect.ValueOf(msg))

ret:=reflect.ValueOf(handler).Call(params)//通過反射機制調用函數
err:=ret[0].Interface()
iferr==nil{
returnnil
}
returnerr.(error)
}

對于AddHandlerCtxDispatchCtx這個2個方法基本上是一樣的,只不過多了一個上下文參數,可以拿來做超時控制或者其它用途。

2.訂閱和發布

除此之外,還有2個方法AddEventListenerPublish,即事件的訂閱和發布。

func(b*InProcBus)AddEventListener(handlerHandlerFunc){
handlerType:=reflect.TypeOf(handler)
eventName:=handlerType.In(0).Elem().Name()
_,exists:=b.listeners[eventName]
if!exists{
b.listeners[eventName]=make([]HandlerFunc,0)
}
b.listeners[eventName]=append(b.listeners[eventName],handler)
}

查看源碼可以得知,可以給一個事件注冊多個handler函數,而Publish的時候則是依次調用注冊的函數,邏輯也不復雜。

func(b*InProcBus)Publish(msgMsg)error{
varmsgName=reflect.TypeOf(msg).Elem().Name()
varlisteners=b.listeners[msgName]

varparams=make([]reflect.Value,1)
params[0]=reflect.ValueOf(msg)

for_,listenerHandler:=rangelisteners{
ret:=reflect.ValueOf(listenerHandler).Call(params)
e:=ret[0].Interface()
ife!=nil{
err,ok:=e.(error)
ifok{
returnerr
}
returnfmt.Errorf("expectedlistenertoreturnanerror,got'%T'",e)
}
}
returnnil
}

這里面有一點不好,所有訂閱函數的調用是順序的,并沒有使用協程,所以如果注冊了很多個函數,這樣效率也不高啊。

3.好處

可能有人會好奇,為什么明明可以直接調用函數就行,為啥非得繞個彎子,整這么復雜?

況且,每次調用都得使用反射機制,性能也不行。

我覺得主要有以下幾點:

1.這種寫法邏輯清晰,解耦

2.方便單元測試

3.性能不是最大考量,雖然說反射會降低性能

原文標題:Golang 事件系統 Event Bus

文章出處:【微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 總線
    +關注

    關注

    10

    文章

    3040

    瀏覽量

    91657
  • 開源
    +關注

    關注

    3

    文章

    4203

    瀏覽量

    46125
  • 代碼
    +關注

    關注

    30

    文章

    4967

    瀏覽量

    73954

原文標題:Golang 事件系統 Event Bus

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    基于PXIe總線的多板卡通道同步機制研究

    1引言在上一篇《基于PXIe的單板多通道同步機制研究》中,我們重點討論了在同一塊PXIe數據采集卡內部,如何通過統一時間基準、統一采樣時鐘與統一啟動觸發,實現各通道在時間軸上的嚴格對齊。然而在實際
    的頭像 發表于 02-03 14:20 ?516次閱讀
    基于PXIe<b class='flag-5'>總線</b>的多板卡通道同步<b class='flag-5'>機制</b>研究

    請問休眠模式下的定時喚醒機制如何實現

    休眠模式下的定時喚醒機制如何實現
    發表于 12-24 07:58

    CW32系統總線有哪些?

    ?系統總線 實現 M0+ 微處理器的外設總線總線矩陣的連接。 ?DMA 總線 實現 DMA
    發表于 12-15 07:54

    CW32總線介紹

    ?系統總線 實現 M0+ 微處理器的外設總線總線矩陣的連接。 ?DMA 總線 實現 DMA
    發表于 12-12 06:21

    基于IAP功能實現遠程升級,如何設計Flash雙Bank熱切換的回滾機制

    基于IAP功能實現遠程升級時,如何設計Flash雙Bank熱切換的回滾機制
    發表于 11-21 07:26

    放大器保護機制的技術原理與實現策略

    現代電子測量系統中,功率放大器和高壓放大器通過多級保護機制(過流、過壓、過溫)確保設備穩定運行,具備自適應和智能控制功能
    的頭像 發表于 10-20 09:41 ?308次閱讀

    如何利用Trace機制實現LLCP預覽功能

    在藍牙協議棧開發過程中,有時需要預先知道 LLCP。本文將介紹如何利用 Trace 機制實現 LLCP 預覽功能。
    的頭像 發表于 10-09 17:55 ?1937次閱讀

    教程來啦!LuatOS中的消息通信機制詳解及其應用場景

    在資源受限的嵌入式環境中,LuatOS采用消息機制實現模塊間解耦與高效通信。通過預定義消息名稱(如“new_msg”),開發者可輕松構建響應式程序結構。接下來我們將深入剖析其實現原理與典型使用方法
    的頭像 發表于 09-26 18:59 ?424次閱讀
    教程來啦!LuatOS中的消息通信<b class='flag-5'>機制</b>詳解及其應用場景

    【HZ-T536開發板免費體驗】5、安裝sqlite3和使用golang讀寫數據庫

    如果想在嵌入式設備上實現簡單的設備管理功能,需要數據庫和服務后端程序。服務端程序,我更傾向使用golang實現。 安裝sqlite3,使用ubuntu環境,可以直接用apt install安裝程序
    發表于 08-26 00:04

    ADI安全產品如何簡化不同機器人控制系統中安全機制實現

    我們將探討各種機器人安全用例,展示ADI的安全產品如何簡化不同機器人控制系統中安全機制實現
    的頭像 發表于 08-12 10:43 ?1.2w次閱讀
    ADI安全產品如何簡化不同機器人控制系統中安全<b class='flag-5'>機制</b>的<b class='flag-5'>實現</b>

    CAN總線采樣點不一致的危害

    參數,遵循CiA等行業標準,并使用位定時計算工具。通過合理的配置和測試,CAN總線可以實現高效、穩定的通信,滿足汽車和工業應用的嚴格要求。
    發表于 06-07 08:55

    如何評估CAN總線信號質量

    ,量化總線性能,幫助識別總線整體健康狀況。 成功率評估標準如下所示: 由于CAN總線的CRC校驗機制,錯誤幀不會被節點接收,但會占用總線
    發表于 06-07 08:46

    NVMe IP之AXI4總線分析

    1AXI4總線協議 AXI4總線協議是由ARM公司提出的一種片內總線協議 ,旨在實現SOC中各模塊之間的高效可靠的數據傳輸和管理。AXI4協議具有高性能、高吞吐量和低延遲等優點,在SO
    發表于 06-02 23:05

    如何驗證CAN控制器的錯誤響應機制

    使用ZPS-CANFD設備驗證CAN控制器的錯誤響應過程。CAN控制器的錯誤管理機制是保障CAN總線通信可靠性的關鍵機制,它能檢測并處理多種錯誤情況,即位錯誤、填充錯誤、C
    的頭像 發表于 04-30 18:24 ?849次閱讀
    如何驗證CAN控制器的錯誤響應<b class='flag-5'>機制</b>?