chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Golang事件總線機(jī)制的實(shí)現(xiàn)

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

掃碼添加小助手

加入工程師交流群

【導(dǎo)讀】本文介紹了事件總線實(shí)現(xiàn)。

最近在學(xué)習(xí)開(kāi)源項(xiàng)目Grafana的代碼,發(fā)現(xiàn)作者實(shí)現(xiàn)了一個(gè)事件總線的機(jī)制,在項(xiàng)目里面大量應(yīng)用,效果也非常好,代碼也比較簡(jiǎn)單,介紹給大家看看。

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

1.注冊(cè)和調(diào)用

在這個(gè)項(xiàng)目里面隨處可見(jiàn)這種寫(xiě)法:

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
}
}

關(guān)鍵是bus.Dispatch(&query)這段代碼,它的參數(shù)是一個(gè)結(jié)構(gòu)體GetAlertByIdQuery,內(nèi)容如下:

typeGetAlertByIdQuerystruct{
Idint64
Result*Alert
}

根據(jù)名字可以看出這個(gè)方法就是通過(guò)Id去查詢Alert,其中Alert結(jié)構(gòu)體就是結(jié)果對(duì)象,這里就不貼出來(lái)了。

通過(guò)查看源碼可以得知,Dispatch背后是調(diào)用了GetAlertById這個(gè)方法,然后把結(jié)果賦值到query參數(shù)的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
}

問(wèn)題來(lái)了,這是怎么實(shí)現(xiàn)的呢?Dispatch到底做了哪些操作?這樣做有什么好處?

下面我來(lái)一一解答:

首先,在Dispatch之前,你需要先注冊(cè)這個(gè)方法,也就是調(diào)用AddHandler,在這個(gè)項(xiàng)目里面可以看到init函數(shù)里面有大量這樣的代碼:

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

其實(shí)這個(gè)方法的邏輯也很簡(jiǎn)單,所謂注冊(cè)也就是把通過(guò)一個(gè)map把函數(shù)名和對(duì)應(yīng)的函數(shù)做一個(gè)映射關(guān)系保存起來(lái),當(dāng)我們Dispatch的時(shí)候其實(shí)就是通過(guò)參數(shù)名查找之前注冊(cè)過(guò)的函數(shù),然后通過(guò)反射調(diào)用該函數(shù)。

Bus結(jié)構(gòu)體里面有幾個(gè)map成員,在這個(gè)項(xiàng)目里面作者定義了3種不同類(lèi)型的handler,一種是普通的handler,也就是剛才展示的那種,第二種是帶上下文的handler,還有一種則是事件訂閱用到的handler,我們給一個(gè)事件注冊(cè)多個(gè)監(jiān)聽(tīng)者,當(dāng)事件觸發(fā)的時(shí)候會(huì)依次調(diào)用多個(gè)監(jiān)聽(tīng)函數(shù),其實(shí)就是一個(gè)觀察者模式。

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

下面就看看具體的源碼,AddHandler方法內(nèi)容如下:

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

Dispatch方法的源碼如下:

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

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

ret:=reflect.ValueOf(handler).Call(params)//通過(guò)反射機(jī)制調(diào)用函數(shù)
err:=ret[0].Interface()
iferr==nil{
returnnil
}
returnerr.(error)
}

對(duì)于AddHandlerCtxDispatchCtx這個(gè)2個(gè)方法基本上是一樣的,只不過(guò)多了一個(gè)上下文參數(shù),可以拿來(lái)做超時(shí)控制或者其它用途。

2.訂閱和發(fā)布

除此之外,還有2個(gè)方法AddEventListenerPublish,即事件的訂閱和發(fā)布。

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)
}

查看源碼可以得知,可以給一個(gè)事件注冊(cè)多個(gè)handler函數(shù),而Publish的時(shí)候則是依次調(diào)用注冊(cè)的函數(shù),邏輯也不復(fù)雜。

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
}

這里面有一點(diǎn)不好,所有訂閱函數(shù)的調(diào)用是順序的,并沒(méi)有使用協(xié)程,所以如果注冊(cè)了很多個(gè)函數(shù),這樣效率也不高啊。

3.好處

可能有人會(huì)好奇,為什么明明可以直接調(diào)用函數(shù)就行,為啥非得繞個(gè)彎子,整這么復(fù)雜?

況且,每次調(diào)用都得使用反射機(jī)制,性能也不行。

我覺(jué)得主要有以下幾點(diǎn):

1.這種寫(xiě)法邏輯清晰,解耦

2.方便單元測(cè)試

3.性能不是最大考量,雖然說(shuō)反射會(huì)降低性能

原文標(biāo)題:Golang 事件系統(tǒng) Event Bus

文章出處:【微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 總線
    +關(guān)注

    關(guān)注

    10

    文章

    3029

    瀏覽量

    91465
  • 開(kāi)源
    +關(guān)注

    關(guān)注

    3

    文章

    4122

    瀏覽量

    45764
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4955

    瀏覽量

    73490

原文標(biāo)題:Golang 事件系統(tǒng) Event Bus

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    請(qǐng)問(wèn)休眠模式下的定時(shí)喚醒機(jī)制如何實(shí)現(xiàn)?

    休眠模式下的定時(shí)喚醒機(jī)制如何實(shí)現(xiàn)?
    發(fā)表于 12-24 07:58

    CW32系統(tǒng)總線有哪些?

    ?系統(tǒng)總線 實(shí)現(xiàn) M0+ 微處理器的外設(shè)總線總線矩陣的連接。 ?DMA 總線 實(shí)現(xiàn) DMA
    發(fā)表于 12-15 07:54

    CW32總線介紹

    ?系統(tǒng)總線 實(shí)現(xiàn) M0+ 微處理器的外設(shè)總線總線矩陣的連接。 ?DMA 總線 實(shí)現(xiàn) DMA
    發(fā)表于 12-12 06:21

    基于IAP功能實(shí)現(xiàn)遠(yuǎn)程升級(jí),如何設(shè)計(jì)Flash雙Bank熱切換的回滾機(jī)制?

    基于IAP功能實(shí)現(xiàn)遠(yuǎn)程升級(jí)時(shí),如何設(shè)計(jì)Flash雙Bank熱切換的回滾機(jī)制?
    發(fā)表于 11-21 07:26

    放大器保護(hù)機(jī)制的技術(shù)原理與實(shí)現(xiàn)策略

    現(xiàn)代電子測(cè)量系統(tǒng)中,功率放大器和高壓放大器通過(guò)多級(jí)保護(hù)機(jī)制(過(guò)流、過(guò)壓、過(guò)溫)確保設(shè)備穩(wěn)定運(yùn)行,具備自適應(yīng)和智能控制功能
    的頭像 發(fā)表于 10-20 09:41 ?216次閱讀

    如何利用Trace機(jī)制實(shí)現(xiàn)LLCP預(yù)覽功能

    在藍(lán)牙協(xié)議棧開(kāi)發(fā)過(guò)程中,有時(shí)需要預(yù)先知道 LLCP。本文將介紹如何利用 Trace 機(jī)制實(shí)現(xiàn) LLCP 預(yù)覽功能。
    的頭像 發(fā)表于 10-09 17:55 ?1739次閱讀

    教程來(lái)啦!LuatOS中的消息通信機(jī)制詳解及其應(yīng)用場(chǎng)景

    在資源受限的嵌入式環(huán)境中,LuatOS采用消息機(jī)制實(shí)現(xiàn)模塊間解耦與高效通信。通過(guò)預(yù)定義消息名稱(chēng)(如“new_msg”),開(kāi)發(fā)者可輕松構(gòu)建響應(yīng)式程序結(jié)構(gòu)。接下來(lái)我們將深入剖析其實(shí)現(xiàn)原理與典型使用方法
    的頭像 發(fā)表于 09-26 18:59 ?323次閱讀
    教程來(lái)啦!LuatOS中的消息通信<b class='flag-5'>機(jī)制</b>詳解及其應(yīng)用場(chǎng)景

    【HZ-T536開(kāi)發(fā)板免費(fèi)體驗(yàn)】5、安裝sqlite3和使用golang讀寫(xiě)數(shù)據(jù)庫(kù)

    如果想在嵌入式設(shè)備上實(shí)現(xiàn)簡(jiǎn)單的設(shè)備管理功能,需要數(shù)據(jù)庫(kù)和服務(wù)后端程序。服務(wù)端程序,我更傾向使用golang來(lái)實(shí)現(xiàn)。 安裝sqlite3,使用ubuntu環(huán)境,可以直接用apt install安裝程序
    發(fā)表于 08-26 00:04

    ADI安全產(chǎn)品如何簡(jiǎn)化不同機(jī)器人控制系統(tǒng)中安全機(jī)制實(shí)現(xiàn)

    我們將探討各種機(jī)器人安全用例,展示ADI的安全產(chǎn)品如何簡(jiǎn)化不同機(jī)器人控制系統(tǒng)中安全機(jī)制實(shí)現(xiàn)。
    的頭像 發(fā)表于 08-12 10:43 ?1.1w次閱讀
    ADI安全產(chǎn)品如何簡(jiǎn)化不同機(jī)器人控制系統(tǒng)中安全<b class='flag-5'>機(jī)制</b>的<b class='flag-5'>實(shí)現(xiàn)</b>

    CAN總線采樣點(diǎn)不一致的危害

    參數(shù),遵循CiA等行業(yè)標(biāo)準(zhǔn),并使用位定時(shí)計(jì)算工具。通過(guò)合理的配置和測(cè)試,CAN總線可以實(shí)現(xiàn)高效、穩(wěn)定的通信,滿足汽車(chē)和工業(yè)應(yīng)用的嚴(yán)格要求。
    發(fā)表于 06-07 08:55

    NVMe IP之AXI4總線分析

    1AXI4總線協(xié)議 AXI4總線協(xié)議是由ARM公司提出的一種片內(nèi)總線協(xié)議 ,旨在實(shí)現(xiàn)SOC中各模塊之間的高效可靠的數(shù)據(jù)傳輸和管理。AXI4協(xié)議具有高性能、高吞吐量和低延遲等優(yōu)點(diǎn),在SO
    發(fā)表于 06-02 23:05

    如何驗(yàn)證CAN控制器的錯(cuò)誤響應(yīng)機(jī)制?

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

    Java的SPI機(jī)制詳解

    作者:京東物流 楊葦葦 1.SPI簡(jiǎn)介 SPI(Service Provicer Interface)是Java語(yǔ)言提供的一種接口發(fā)現(xiàn)機(jī)制,用來(lái)實(shí)現(xiàn)接口和接口實(shí)現(xiàn)的解耦。簡(jiǎn)單來(lái)說(shuō),就是系統(tǒng)只需要定義
    的頭像 發(fā)表于 03-05 11:35 ?1245次閱讀
    Java的SPI<b class='flag-5'>機(jī)制</b>詳解

    CAN總線的電路保護(hù)器件,通過(guò)二極管陣列的工作原理實(shí)現(xiàn)了對(duì)CAN總線的高效保護(hù)

    CAN總線的電路保護(hù)器件,通過(guò)二極管陣列的工作原理實(shí)現(xiàn)了對(duì)CAN總線的高效保護(hù)。它具有高速響應(yīng)、低電流泄露、低電壓降和高溫工作的特點(diǎn),適用于汽車(chē)和工業(yè)控制系統(tǒng)中的CAN總線保護(hù)
    的頭像 發(fā)表于 03-03 13:26 ?1003次閱讀
    CAN<b class='flag-5'>總線</b>的電路保護(hù)器件,通過(guò)二極管陣列的工作原理<b class='flag-5'>實(shí)現(xiàn)</b>了對(duì)CAN<b class='flag-5'>總線</b>的高效保護(hù)

    SPI通信總線概述和Verilog實(shí)現(xiàn)

    SPI = Serial Peripheral Interface,是串行外圍設(shè)備接口,是一種高速,全雙工,同步的通信總線。
    的頭像 發(fā)表于 02-07 14:28 ?2148次閱讀
    SPI通信<b class='flag-5'>總線</b>概述和Verilog<b class='flag-5'>實(shí)現(xiàn)</b>