如何更酷地實現 Go 程式熱開關功能
在介紹新方案之前,我們先回顧一下,在 Go 程式中,pprof 是如何做的。
介面呼叫
對程式進行效能取樣,可能會影響到它的服務能力。因此,線上採樣一般是在指定的小塊時間範圍內進行,需要有效的開關控制。
為了做到這一點,我們一般採用在程式碼中引入 net/http/pprof 套件(其 init 函數綁定了路由功能函數)的方式。外部存取指定連接埠的 HTTP 服務時開啟採樣功能,採樣時間結束後,即關閉採集。
實作程式碼如下圖
package main import ( "net/http" _ "net/http/pprof" ) func main() { go func() { _ = http.ListenAndServe(":8080", nil) }() ... }
這種做法,當然沒什麼問題。我們可以學習它,將其他的開關功能也做成 HTTP 服務。但,還有其他更酷的方式嗎?
信号通知
在信号处理与 Go 程序的优雅退出一文中,我们谈论过信号机制,它用以向应用程序发送某种事件通知。
我们可以将基于接口触发的方式改为信号通知。
首先,构造采样功能函数(对应于 net/http/pprof 包下 init 函数中绑定的路由功能函数)。
func RegisterSignalForProfiling(sig os.Signal) { ch := make(chan os.Signal) started := false signal.Notify(ch, sig) go func() { var memoryProfile, cpuProfile, traceProfile *os.File for range ch { if started { pprof.StopCPUProfile() trace.Stop() pprof.WriteHeapProfile(memoryProfile) memoryProfile.Close() cpuProfile.Close() traceProfile.Close() started = false } else { cpuProfile, _ = os.Create("cpu.pprof") memoryProfile, _ = os.Create("memory.pprof") traceProfile, _ = os.Create("runtime.trace") pprof.StartCPUProfile(cpuProfile) trace.Start(traceProfile) started = true } } }() }
在上述函数中,我们定义了接收信号通道<span style="font-size: 15px;">ch</span>
,通过<span style="font-size: 15px;">signal.Notify(ch, sig)</span>
将指定的通知信号<span style="font-size: 15px;">sig</span>
与<span style="font-size: 15px;">ch</span>
进行绑定。<span style="font-size: 15px;">for range ch</span>
将阻塞等待外部信号<span style="font-size: 15px;">sig</span>
,随着<span style="font-size: 15px;">sig</span>
信号的到来,交替进入开启或关闭采样的逻辑。
在<span style="font-size: 15px;">main</span>
函数中,就可以这样替代<span style="font-size: 15px;">http.ListenAndServe(":8080", nil)</span>
了。
package main import ( "syscall" ... ) func main() { RegisterSignalForProfiling(syscall.Signal(31)) ... }
在 linux 系统,可以通过<span style="font-size: 15px;">kill -signal_number pid</span>
命令向程序发送指定信号。
如上代码所示,我们硬编码指定的采样开关信号值是 31。因此,当程序运行起来后,我们在控制台输入<span style="font-size: 15px;">kill -31 pid</span>
命令,即可开启采样,再次输入<span style="font-size: 15px;">kill -31 pid</span>
命令,就关闭了采样。
依葫芦画瓢,我们再来一个打印 goroutine 堆栈信息的热开关函数,是不是很酷?
func RegisterSignalForPrintStack(sig os.Signal) { ch := make(chan os.Signal) signal.Notify(ch, sig) go func() { for range ch { buffer := make([]byte, 1024*1024*4) runtime.Stack(buffer, true) fmt.Println(string(buffer)) } }() }
总结
热开关是一个很简单常用的功能,无非是选择何种触发与等待方式。基于接口的调用更适合于远程控制,基于信号则便于本地控制。
以上是如何更酷地實現 Go 程式熱開關功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在開發中,我們經常會有熱開關的需求,即特定功能在程式運作中的適當時候對它進行開啟或關閉。例如效能分析中所使用的 pprof 取樣,就是一種典型的熱開關。本文將討論如何將這種熱開關做得更酷。

取得應用程式的運作指標,可以讓我們更了解它的實際狀況。將這些指標對接到 prometheus、zabbix 等監控系統,能夠對應用程式持續偵測,發現異常可以及時警告並處理。

Go是一種受歡迎的程式語言,與其他程式語言相比,Go的編譯速度較快,記憶體消耗較少。但是,有時候我們的Go程式會因為缺乏依賴而導致編譯失敗。那麼,為什麼會發生這種情況呢?首先,我們要先了解Go編譯的原理。 Go是靜態編譯型語言,也就是在編譯時就將程式翻譯成機器碼,然後直接執行。與動態編譯型語言相比,Go的編譯過程更為複雜,因為在編譯之前,需要將所有要使用的套件都轉

最近,越來越多的人開始使用GoQUIC來建立網路應用程式。由於其高效的傳輸性能和可靠性,GoQUIC已成為許多專案的首選。但是,在實際使用過程中,一些開發者發現他們的Go程式無法正確使用GoQUIC程式庫。下面,我們就來分析一下可能導致Go程式無法正常使用GoQUIC函式庫的原因。 1.版本問題首先,你要確定你的GoQUIC版本是否是最新的。 GoQUIC經常更新,如果

Go是一種高效率的程式語言,提供了記憶體管理方面的特殊機制。然而,即使在使用這種語言的時候也有可能出現一些問題,例如「outofmemory」錯誤。那麼,為什麼我的Go程式會出現這種錯誤呢?記憶體洩漏記憶體洩漏是一種常見的問題,它在Go語言中同樣存在。當你的Go程式分配了大量的內存,並在執行某些操作後沒有徹底釋放這些內存時,就會出現內存洩漏問題。如果出現記憶體洩漏

在公司的不斷發展中,一開始大多是大單體,改造慢了,一個倉庫會有使用十幾年的情況,倉庫的規模基本上是不斷增大的過程。

在使用Go語言進行開發過程中,難免會遇到各種不同的錯誤。其中一個常見的錯誤是“coredumped”,這個錯誤訊息可能會讓一些開發者感到困惑。本文將說明這個錯誤的原因以及如何解決它。 「coredumped」的意思在Linux作業系統中,「coredumped」是一種錯誤訊息,它表示一個行程在執行過程中意外退出,並且已經產生了一個所謂的「core」檔案。這

Golang(Go)是一門語言,它非常擅長處理錯誤和異常情況。與其他語言不同,Go透過簡單而有效的錯誤處理機制來處理異常情況。儘管Go的錯誤處理機制非常強大且靈活,但某些程式設計師在程式中實作錯誤處理時仍會遇到麻煩。這篇文章旨在幫助解決關於為什麼Go程式中的異常處理無效的問題,以及如何正確地處理異常情況。在Go中無效的異常處理通常是因為程式設計師未正確處理錯誤或誤
