簡體   English   中英

http.Handle 包裝器模式 -> 堆棧會膨脹嗎?

[英]http.Handle wrapper pattern -> will the stack be bloated?

我正在做第一個生產網絡服務,所以我對語言和一些概念/模式很陌生。

我的問題與處理程序有關,並且基本上與如何在不降低性能的情況下提取重復代碼有關。

我遇到了包裝http.Handlehttp.HandlerFunc以清理代碼的模式。 例如,這里使用適配器模式的這篇博客文章https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.hvsc236iv

它可能會以這樣的方式結束(從 blob 帖子中復制):

http.Handle("/", Adapt(indexHandler, AddHeader("Server", "Mine"),
                                 CheckAuth(providers),
                                 CopyMgoSession(db),
                                 Notify(logger), 
                               )

這基本上是一個深度嵌套的函數調用。

我的問題是堆棧中發生了什么以及服務的性能? 使用這種模式,每個用戶請求都會向堆棧中添加至少 5 個堆棧幀。 這是可以接受的,還是會在流量高時對性能產生負面影響?

鏈接中間件基本上只是讓鏈的處理程序調用下一個,通常基於是否一切順利的條件。 或者在另一種方法中,某些外部機制可能會一個一個地調用處理程序。

但是,所有事情都歸結為將調用處理程序。 Handler.ServeHTTP()方法如下所示:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

一個簡單的方法,有 2 個參數,沒有返回值。 參數的類型為http.ResponseWriter (接口類型)和*http.Request (指針類型)。

因此,對處理程序的ServeHTTP()的調用涉及兩件事:復制其參數 - 由於它們很小,因此速度很快,並且實際進行調用(處理堆棧更新,例如創建新的堆棧幀,記錄返回地址,保存使用過的寄存器,並執行被調用的函數) - 這也非常快(請參閱答案末尾的引用)。

那么你應該擔心調用函數嗎? 不。與包含所有內容的處理程序相比,這會降低性能嗎? 是的。 差異顯着嗎? 不。處理 HTTP 請求可能需要數百毫秒(包括網絡延遲)。 在處理程序中調用 10 個函數不會明顯變慢。

如果您擔心由於函數調用而導致的性能損失,那么您的應用程序將由一個main()函數組成。 顯然沒有人想要那樣。 您創建函數以將最初的大問題分解為較小的問題(遞歸直到它“足夠小”以獨立存在),您可以獨立於其他人監督重用測試,然后將大問題從較小的問題中組裝起來. 這實際上不是性能問題,而是可維護性可重用性問題 您真的想將檢查用戶身份的 100 行代碼復制到所有 10 個不同的處理程序嗎?

最后一件事。 您是否應該擔心“消耗”堆棧(導致堆棧溢出錯誤)? 答案是不。 一個 goroutine 以一個 4096 字節的小堆棧開始,它可以根據需要增長和縮小,而沒有用完的風險。 為什么 Goroutine 的堆棧是無限的? 常見問題解答中也有詳細說明:為什么使用 goroutines 而不是線程?

為了使堆棧變小,Go 的運行時使用可調整大小的有界堆棧。 一個新創建的 goroutine 被賦予幾千字節,這幾乎總是足夠的。 如果不是,運行時會自動增加(和收縮)用於存儲堆棧的內存,從而允許許多 goroutine 存在於適度的內存中。 每個函數調用的 CPU 開銷平均約為 3 條廉價指令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM