在平衡數據和軟體工程師的過程中,我總是在GoLang 中尋找一些不同的東西來學習,了解它是如何工作的,並將其應用到比我在互聯網上找到的一些基本傳統課程和文章更複雜的事情上。在這篇短文中,我將報告並演示我如何透過 Go Routines 實現,使用 Ticker 來模擬應用程式的心跳(「我還活著」)的時間包,以及通道的使用等。
對許多人來說,確保呼叫某個函數的人知道該函數是否正在花費時間、正在處理或處於鎖定狀態是極其重要的,這對許多人來說並不是新聞。也就是說,出現了其他幾個術語,例如追蹤、指標、連接性等,這些術語已在監控應用程式中引入,這些應用程式在大多數情況下使用安裝在應用程式伺服器上的代理程式來收集指標並將其發送到可視化所有(或幾乎)您的申請狀態。這些工具中我們有DataDog、NewRelic、Slack、Grafana、Jaeger等
當我研究和思考創建一些快速簡單的東西來解決一些更高級的 Go 概念時,我創建了一個相對簡單的應用程序,它利用了心跳模式。無論誰給我打電話,都會收到結果,同時也會收到我是否仍然活躍的訊息。在更高級的場景中,根據某些業務特殊性自訂實際上是活動的應用程式可能會很有趣,因為Prometheus 的簡單實作可以解決這種情況(應用程式是活動的嗎?CPU、記憶體、打開的goroutine),但是沒有同步和可自訂的回饋。
在結構方面,我只使用 go mod 在套件中建立了三個檔案:
這部分Go程式碼定義了一個名為「dictionary」的變量,它是一個將符文類型字元與字串關聯起來的對應。
每個地圖條目都是一個鍵(符文)和一個值(字串)。在下面的範例中,鍵是字母表中的小寫字母,值是與每個字母關聯的名稱。例如,字母「a」與名稱「airton」相關聯,字母「b」與名稱「bruno」相關聯,依此類推:
package heartbeat var dicionario = map[rune]string{ 'a': "airton", 'b': "bruno", 'c': "carlos", 'd': "daniel", 'e': "eduardo", 'f': "felipe", 'g': "gustavo", }
我在完整程式碼之後更好地解釋了程式碼的每個部分:
package heartbeat import ( "context" "fmt" "time" ) func ProcessingTask( ctx context.Context, letras chan rune, interval time.Duration, ) (<-chan struct{}, <-chan string) { heartbeats := make(chan struct{}, 1) names := make(chan string) go func() { defer close(heartbeats) defer close(names) beat := time.NewTicker(interval) defer beat.Stop() for letra := range letras { select { case <-ctx.Done(): return case <-beat.C: select { case heartbeats <- struct{}{}: default: } case names <- dicionario[letra]: lether := dicionario[letra] fmt.Printf("Letra: %s \n", lether) time.Sleep(3 * time.Second) // Simula um tempo de espera para vermos o hearbeats } } }() return heartbeats, names }
package heartbeat import ( "context" "fmt" "time" )
這裡有我的心跳包,它將負責實現在處理任務時以特定時間間隔發送「心跳」的功能。為此,我需要上下文(上下文管理)、fmt(用於字串格式化)和時間來進行時間控制。
func ProcessingTask ( ctx context.Context, letras chan rune, interval time.Duration, ) (<-chan struct{}, <-chan string) {
這是ProcessingTask函數的定義,它接受ctx上下文、字母通道(接收Unicode字元的通道)和時間間隔作為參數。此函數傳回兩個通道:一個心跳通道,為每個「心跳」發送一個空結構;一個名稱通道,發送與收到的每個字元對應的字母名稱。
heartbeats := make(chan struct{}, 1) names := make(chan string)
這兩行創建了兩個通道:heartbeats 是一個緩衝通道,容量為一個元素,names 是一個無緩衝通道。
go func() defer close(heartbeats) defer close(names) beat := time.NewTicker(interval) defer beat.Stop() for letra := range letras { select { case <-ctx.Done(): return case <-beat.C: select { case heartbeats <- struct{}{}: default: } case names <- dicionario[letra]: lether := dicionario[letra] fmt.Printf("Letra: %s \n", lether) time.Sleep(3 * time.Second) // Simula um tempo de espera para vermos o hearbeats } } }() return heartbeats, names
這是一個匿名goroutine(或在新執行緒中運行的匿名函數),執行ProcessingTask函數的主要邏輯。它使用 for-range 循環從字母通道讀取字元。在循環內,使用 select 從可用選項中選擇要執行的操作:
最後,函數傳回心跳並命名通道。
task_test.go
package heartbeat var dicionario = map[rune]string{ 'a': "airton", 'b': "bruno", 'c': "carlos", 'd': "daniel", 'e': "eduardo", 'f': "felipe", 'g': "gustavo", }
這裡我為前面解釋過的ProcessingTask 函數建立了一個Go 單元測試。 TestProcessingTask 測試函數會建立一個逾時為 20 秒的上下文和一個 Unicode 字元(字母)通道。然後,匿名 Goroutine 將歌詞發送到歌詞通道。然後使用上下文、Unicode 字元通道和時間間隔呼叫ProcessingTask 函數。它返回兩個通道,一個心跳通道和一個單字通道。
然後,測試函數使用 select 運行無限循環,從三個通道讀取:上下文、心跳通道和單字通道。
如果上下文被取消,測試循環就會終止。如果收到心跳,則會顯示「Application Up!」列印到標準輸出。如果接收到單字,則測試檢查該單字是否存在於字母字典中。如果不存在,則測試失敗並顯示錯誤訊息。
因此,這個單元測試測試我們的ProcessingTask函數,該函數從一個通道接收字符,將字母名稱發送到另一個通道,並在我使用時間限制的上下文中運行時發出“心跳”。啊……它還會檢查發送到單字通道的字母名稱是否存在於字典中。
這段 Go 程式碼詮釋了 Go 語言和單元測驗的一些重要概念:
我的 GitHub 上的完整專案:https://github.com/AirtonLira/heartbeatsGolang
領英 - Airton Lira Junior
以上是在 Golang 中使用心跳模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!