Go語言事件總線EventBus本地事件總線系統的完整實現框架

在Go語言中,EventBus是一種非常有用的工具,它通過事件驅動的編程方式,幫助開發者實現組件之間的解耦,提高代碼的可維護性和擴展性。

背景

  • 軟件架構的發展需求:隨著軟件系統的規模和復雜度不斷增大,傳統的緊耦合架構在開發、測試、部署和維護等方面都面臨著諸多挑戰。組件之間的高度依賴使得代碼難以修改和擴展,一旦某個組件發生變化,可能需要修改多個相關聯的組件。EventBus所代表的事件驅動架構應運而生,它允許組件之間通過事件進行松散耦合的通信,降低了組件之間的依賴關系,使得系統更加靈活和可維護。

  • Go語言的并發特性:Go語言以其強大的并發能力而聞名,goroutine的輕量級和高效的特性使得并發編程變得簡單而高效。EventBus與Go語言的并發特性相結合,可以更好地實現異步事件處理,充分發揮Go語言在高并發場景下的優勢,提高系統的響應性和吞吐量。

  • 微服務架構的興起:在微服務架構中,系統被拆分成多個小型的、獨立的服務,這些服務之間需要進行高效的通信和協作。EventBus提供了一種輕量級的通信機制,使得微服務之間可以通過發布和訂閱事件來實現解耦的交互,避免了服務之間的直接依賴,同時也支持異步的消息傳遞,提高了系統的可用性和可擴展性。

簡介

  • 基本概念:EventBus是一種設計模式,它充當一個中央集散地,負責在事件的發布者和訂閱者之間進行消息的傳遞。在Go語言中,通過使用EventBus庫,開發者可以輕松地實現事件的發布、訂閱和處理。當某個事件發生時,發布者將事件發送到EventBus,EventBus根據事件的類型或主題,將事件通知給所有訂閱了該事件的訂閱者,訂閱者接收到事件后執行相應的處理邏輯。

  • 主要功能:提供了事件的發布與訂閱功能,使得組件之間可以通過事件進行通信,而無需直接調用彼此的方法。支持異步事件處理,訂閱者可以根據需要選擇同步或異步的方式來處理事件,從而提高系統的響應速度和并發性能。具備事件的過濾和路由功能,可以根據事件的類型、主題或其他條件,將事件精準地分發給感興趣的訂閱者,提高事件處理的效率和準確性。

  • 優勢:解耦組件之間的依賴關系,使得各個組件可以獨立開發、測試和部署,提高了代碼的可維護性和可擴展性。簡化了事件驅動編程的實現,通過簡單的API調用,就可以實現事件的發布和訂閱,降低了開發難度和工作量。支持異步消息處理,可以提高系統的響應性和吞吐量,適用于高并發場景。提供了靈活的事件處理機制,可以滿足不同類型和復雜度的業務需求,如支持多種事件類型、通配符訂閱等。

安裝

確保您的計算機上安裝了 Go。 在終端中鍵入以下命令:

go get github.com/asaskevich/EventBus

之后,就可以在使用EventBus的時候導入包了。

使用

在文件中添加以下行:*.go

import "github.com/asaskevich/EventBus"

如果你不喜歡使用 long ,你可以對其進行起別名來處理:

import (evbus "github.com/asaskevich/EventBus"
)

簡單案例

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消訂閱事件 %s 失敗: %v\n", "main:calculator", err)}
}

如果你想要面向對象編程進行學習的話,可以對其進行封裝處理:

package mainimport ("fmt""github.com/asaskevich/EventBus"
)type Bus struct {EventBus EventBus.Bus
}func calculator(a int, b int) {fmt.Printf("a + b = "+"%d\n", a+b)
}// Subscribe 方法注冊事件監聽
func (bus *Bus) Subscribe() {err := bus.EventBus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}
}// Publish 方法觸發事件
func (bus *Bus) Publish() {bus.EventBus.Publish("main:calculator", 33, 60)
}// UnSubscribe 取消訂閱
func (bus *Bus) UnSubscribe() {err := bus.EventBus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消訂閱事件 %s 失敗: %v\n", "main:calculator", err)}
}func main() {eventBus := EventBus.New()bus := &Bus{EventBus: eventBus}bus.Subscribe()bus.Publish()bus.UnSubscribe()
}

方法

  • New()
  • Subscribe()
  • SubscribeOnce()
  • Unsubscribe()
  • HasCallback()
  • Publish()
  • SubscribeAsync()
  • SubscribeOnceAsync()
  • WaitAsync()

New()

函數簽名

func New() EventBus

功能

創建一個新的事件總線實例,該實例用于管理事件的訂閱、發布等操作。

應用場景

在需要使用事件總線機制的程序開始時調用,初始化事件總線。

示例代碼

package mainimport ("github.com/asaskevich/EventBus"
)func main() {bus := EventBus.New() // 創建事件總線實例// 后續可使用 bus 進行事件訂閱和發布操作
}

?Subscribe()

函數簽名

func (bus *EventBus) Subscribe(topic string, fn interface{}) error

功能

將一個回調函數訂閱到指定的事件主題上。當該主題的事件被發布時,回調函數會被同步調用。

應用場景

適用于需要同步處理事件的場景,例如更新界面狀態、記錄日志等。

返回錯誤

如果第二個參數傳的不是函數,則會返回錯誤。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)
}

?SubscribeOnce()

函數簽名

func (bus *EventBus) SubscribeOnce(topic string, fn interface{}) error

功能

將一個回調函數訂閱到指定的事件主題上,該回調函數只會在事件第一次發布時被調用,之后自動取消訂閱。

應用場景

適用于只需要處理一次事件的場景,例如初始化操作、一次性通知等。

返回錯誤

如果第二個參數傳的不是函數,則會返回錯誤。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeOnce("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)bus.Publish("main:calculator", 20, 40)  // 第二次發布,calculator不會再執行
}

Unsubscribe()

函數簽名

func (bus *EventBus) Unsubscribe(topic string, fn interface{}) error

功能

從指定的事件主題中取消訂閱指定的回調函數。

應用場景

當不再需要處理某個事件時,調用該函數取消訂閱,釋放資源。

返回錯誤

  1. 事件名稱不存在:當你嘗試取消訂閱一個從未被訂閱過的事件名稱時,Unsubscribe 會返回錯誤。
  2. 處理函數不匹配:若你嘗試用一個和訂閱時不同的處理函數來取消訂閱,Unsubscribe 也會返回錯誤。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消訂閱事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40) // 發布事件,calculator 不會再執行
}

HasCallback()

函數簽名

func (bus *EventBus) HasCallback(topic string) bool

功能

檢查指定的事件主題是否存在已訂閱的回調函數。

應用場景

在發布事件前檢查是否有訂閱者,避免不必要的發布操作;或者在取消訂閱前確認是否有回調函數需要取消。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()// 訂閱事件err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)return}// 檢查是否有訂閱者if bus.HasCallback("main:calculator") {// 有訂閱者,發布事件bus.Publish("main:calculator", 20, 40)} else {fmt.Println("沒有訂閱者,不發布事件")}// 取消訂閱err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消訂閱事件 %s 失敗: %v\n", "main:calculator", err)}
}

Publish()

函數簽名

func (bus *EventBus) Publish(topic string, args ...interface{})

功能

發布一個指定主題的事件,并將參數傳遞給所有訂閱該主題的回調函數。

應用場景

在程序中某個特定事件發生時,調用該函數通知所有訂閱者。例如,在一個聊天應用中,當服務器收到新消息時,發布消息事件通知所有客戶端。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("訂閱事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40) // 發布事件,傳遞參數 20 和 40
}

SubscribeAsync()

函數簽名

func (bus *EventBus) SubscribeAsync(topic string, fn interface{}, transactional bool) error

功能

以異步方式訂閱某個事件,transactional=true 時按順序執行,false 時并發執行。

應用場景

用于后臺異步處理任務,如寫日志、發送郵件等不會阻塞主流程的任務。

返回錯誤

如果第二個參數傳的不是函數,則會返回錯誤。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeAsync("main:calculator", calculator,false)if err != nil {fmt.Printf("異步處理事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)fmt.Println("Main continues...")bus.WaitAsync() // 等待所有異步回調完成
}

?SubscribeOnceAsync()

函數簽名

func (bus *EventBus) SubscribeOnceAsync(topic string, fn interface{}, transactional bool) error

功能

以異步方式訂閱事件,僅觸發一次。

應用場景

用于一次性異步初始化、只執行一次的異步鉤子或遠程調用。

返回錯誤

如果第二個參數傳的不是函數,則會返回錯誤。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeOnceAsync("main:calculator", calculator, false)if err != nil {fmt.Printf("一次性異步處理事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)bus.Publish("main:calculator", 20, 40) // 不會執行bus.WaitAsync()
}

?WaitAsync()

函數簽名

func (bus *EventBus) WaitAsync()

功能

等待所有異步事件處理完成。

應用場景

在程序退出前等待所有異步任務結束,確保不會中斷執行中的任務。

示例代碼

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeAsync("main:calculator", calculator,false)if err != nil {fmt.Printf("異步處理事件 %s 失敗: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)fmt.Println("Main continues...")bus.WaitAsync()
}

完整示例

package mainimport ("fmt""time""github.com/asaskevich/EventBus"
)func main() {// New()bus := EventBus.New()// Subscribe()bus.Subscribe("math:add", func(a int, b int) {fmt.Printf("Add: %d + %d = %d\n", a, b, a+b)})// SubscribeOnce()bus.SubscribeOnce("notify:once", func() {fmt.Println("This message will be shown only once.")})// HasCallback()if bus.HasCallback("math:add") {fmt.Println("Callback for 'math:add' exists.")}// Publish()bus.Publish("math:add", 10, 20)bus.Publish("notify:once")  // 第一次調用,有輸出bus.Publish("notify:once")  // 第二次調用,無輸出// Unsubscribe()printHello := func() { fmt.Println("Hello!") }bus.Subscribe("say:hello", printHello)bus.Publish("say:hello")bus.Unsubscribe("say:hello", printHello)bus.Publish("say:hello") // 已取消訂閱,無輸出// SubscribeAsync()bus.SubscribeAsync("async:greet", func(name string) {time.Sleep(1 * time.Second)fmt.Printf("Hello, %s (from async)\n", name)}, false)// SubscribeOnceAsync()bus.SubscribeOnceAsync("init:once", func() {time.Sleep(1 * time.Second)fmt.Println("Async init done (only once).")}, false)// 異步事件發布bus.Publish("async:greet", "Alice")bus.Publish("init:once")bus.Publish("init:once") // 第二次不會觸發// WaitAsync()fmt.Println("Waiting for async handlers to finish...")bus.WaitAsync()fmt.Println("All async tasks completed.")
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83182.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83182.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83182.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Go語言接口:靈活多態的核心機制

引言 Go語言的接口系統是其??面向對象編程??的核心,它摒棄了傳統語言的類繼承體系,采用獨特的??隱式實現??和??鴨子類型??設計。這種設計使得Go接口既靈活又強大,成為構建松耦合系統的關鍵工具。本文將深入剖析Go接口的實現機制…

DeviceNET轉EtherCAT網關:醫院藥房自動化的智能升級神經中樞

在現代醫院藥房自動化系統中,高效、精準、可靠的設備通信是保障患者用藥安全與效率的核心。當面臨既有支持DeviceNET協議的傳感器、執行器(如藥盒狀態傳感器、機械臂限位開關)需接入先進EtherCAT高速實時網絡時,JH-DVN-ECT疆鴻智能…

android實現使用RecyclerView詳細

顯示頁面代碼&#xff1a;activity_category_inventory.xml代碼&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" xmlns:app"http://schemas.and…

【SpringBoot實戰】優雅關閉服務

文章目錄 一、什么是優雅關閉&#xff1f;二、優雅關閉的核心步驟三、SpringBoot優雅關閉實現四、關鍵注意事項1. 超時時間必須配置2. 信號支持局限性3. 特殊請求處理 五、底層實現原理六、總結 一、什么是優雅關閉&#xff1f; 優雅關閉&#xff08;Graceful Shutdown&#x…

C++哈希表:unordered系列容器詳解

本節目標 1.unordered系列關聯式容器 2.底層結構 3.模擬實現 4.哈希的應用 5.海量數據處理面試題 unordered系列關聯式容器 在c98中&#xff0c;STL提供了底層為紅黑樹結構的一系列關聯式容器&#xff0c;在查詢時效率可以達到logN&#xff0c;即最差的情況下需要比較紅…

java操作服務器文件(把解析過的文件遷移到歷史文件夾地下)

第一步導出依賴 <dependency><groupId>org.apache.sshd</groupId><artifactId>sshd-core</artifactId><version>2.13.0</version></dependency> 第二步寫代碼 public void moveFile( List<HmAnalysisFiles> hmAnalys…

Oracle OCP認證的技術定位怎么樣?

一、引言&#xff1a;Oracle OCP認證的技術定位? Oracle Certified Professional&#xff08;OCP&#xff09;認證是數據庫領域含金量最高的國際認證之一&#xff0c;其核心價值在于培養具備企業級數據庫全生命周期管理能力的專業人才。隨著數字化轉型加速&#xff0c;OCP認證…

TK海外搶單源碼/指定卡單

? 搶單源碼&#xff0c;有指定派單&#xff0c;打針&#xff0c;這套二改過充值跳轉客服 前端vue 后端php 兩端分離 可二開 可以指定卡第幾單&#xff0c;金額多少&#xff0c; 前后端開源 PHP7.2 MySQL5.6 前端要www.域名&#xff0c;后端要admin.域名 前端直接靜態 偽靜…

遠程線程注入

注入簡單來說就是讓別人的程序執行 你想要讓他執行的dll #include<iostream> #include<Windows.h> using namespace std;char szBuffer[] "C:\\Users\\20622\\source\\repos\\Dll1\\Debug\\test.dll"; //dll路徑void RemoteThreadInject(DWORD Pid,PCH…

【Java實戰】集合排序方法與長度獲取方法辨析(易懂版)

一、排序方法 1. 對List排序的兩種方式 方式一Collections.sort() List<Integer> numbers Arrays.asList(3,1,4,2); Collections.sort(numbers); // 直接修改原list → [1,2,3,4]方式二&#xff1a;list.sort()&#xff08;Java8推薦&#xff09; List<String>…

企業級安全實踐:SSL/TLS 加密與權限管理(一)

引言 ** 在數字化轉型的浪潮中&#xff0c;企業對網絡的依賴程度與日俱增&#xff0c;從日常辦公到核心業務的開展&#xff0c;都離不開網絡的支持。與此同時&#xff0c;網絡安全問題也日益嚴峻&#xff0c;成為企業發展過程中不可忽視的重要挑戰。 一旦企業遭遇網絡安全事…

Java 大視界 -- Java 大數據在智能醫療影像數據壓縮與傳輸優化中的技術應用(227)

&#x1f496;親愛的朋友們&#xff0c;熱烈歡迎來到 青云交的博客&#xff01;能與諸位在此相逢&#xff0c;我倍感榮幸。在這飛速更迭的時代&#xff0c;我們都渴望一方心靈凈土&#xff0c;而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識&#xff0c;也…

Python編程基礎(一) | 變量和簡單數據類型

引言&#xff1a;很久沒有寫 Python 了&#xff0c;有一點生疏。這是學習《Python 編程&#xff1a;從入門到實踐&#xff08;第3版&#xff09;》的課后練習記錄&#xff0c;主要目的是快速回顧基礎知識。 練習1&#xff1a; 簡單消息 將一條消息賦給變量&#xff0c;并將其…

鴻蒙 HarmonyOS - SideBarContainer 組件自學指南

在日常開發中&#xff0c;如果你有類似「左側導航 右側內容」的布局需求&#xff0c;比如后臺管理界面、文件管理器、設置頁等&#xff0c;??SideBarContainer?? 是非常值得掌握的組件。它自帶側邊欄和主內容區的分離機制&#xff0c;還支持折疊、拖拽、控制按鈕和多種顯示…

CppCon 2014 學習:Practical Functional Programming

這段內容是對**在 C 中使用函數式編程&#xff08;Functional Programming, FP&#xff09;**可以做什么的簡要介紹&#xff0c;下面是逐條的翻譯與理解&#xff1a; Introduction 簡介 在 C 中使用函數式編程&#xff08;FP&#xff09;可以做什么&#xff1f; 1. 編寫強大…

飛牛NAS+Docker技術搭建個人博客站:公網遠程部署實戰指南

文章目錄 前言1. Docker下載源設置2. Docker下載WordPress3. Docker部署Mysql數據庫4. WordPress 參數設置5. 飛牛云安裝Cpolar工具6. 固定Cpolar公網地址7. 修改WordPress配置文件8. 公網域名訪問WordPress總結 前言 在數字化浪潮中&#xff0c;傳統網站搭建方式正面臨前所未…

ComfyUI+阿里Wan2.1+內網穿透技術:本地AI視頻生成系統搭建實戰

文章目錄 前言1.軟件準備1.1 ComfyUI1.2 文本編碼器1.3 VAE1.4 視頻生成模型 2.整合配置3. 本地運行測試4. 公網使用Wan2.1模型生成視頻4.1 創建遠程連接公網地址 5. 固定遠程訪問公網地址總結 前言 各位技術愛好者&#xff0c;今天為您帶來一組創新性的AI應用方案&#xff01…

n8n:技術團隊的智能工作流自動化助手

在當前數字化時代,自動化已經成為提高效率和減輕人工工作負擔的一大推動力。今天,我們要為大家介紹一款極具潛力的開源項目——n8n,它不僅擁有廣泛的應用場景,還具備內置AI功能,能夠完全滿足技術團隊的高效工作需求。n8n的出現,為技術團隊提供了自由編程與快速自動化構建…

1,QT的編譯教程

目錄 整體流程: 1,新建project文件 2,編寫源代碼 3,打開QT的命令行窗口 4,生成工程文件(QT_demo.pro) 5,生成Make file 6,編譯工程 7,運行編譯好的可執行文件 整體流程: 1,新建project文件 新建文本文件,后綴改為.cpp 2,編寫源代碼

深度學習論文: FastVLM: Efficient Vision Encoding for Vision Language Models

深度學習論文: FastVLM: Efficient Vision Encoding for Vision Language Models FastVLM: Efficient Vision Encoding for Vision Language Models PDF: https://www.arxiv.org/abs/2412.13303 PyTorch代碼: https://github.com/shanglianlm0525/CvPytorch PyTorch代碼: https…