duanbin198788 2016-10-05 09:05
浏览 48
已采纳

http.Handle包装模式->堆栈会膨胀吗?

I am doing a first production webservice in go, so I am quite new to the language and some concepts/patterns.

My question is related to handlers and essentially how to pull out duplicated code without degrading performance.

I have come accross the pattern to wrap either http.Handle or http.HandlerFunc to clean up code. For example this blog post here using an adapter pattern https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.hvsc236iv

It might end up with something like this (copied from the blob post):

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

which is basically a deeply nested function call.

The question I have is what happens in the stack and the performance of the service? With this pattern, every single user request will add at least 5 stack frames to the stack. Is that acceptable or will it have a negative effect on performance when traffic is high?

  • 写回答

1条回答 默认 最新

  • douti0467 2016-10-05 09:45
    关注

    Chaining middlewares is basically just making the handlers of the chain call the next one, often based on a condition whether everything went well. Or in another approach some external mechanism may call handlers one-by-one.

    However, all things come down to that the handlers will be called. The Handler.ServeHTTP() method looks like this:

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

    A simple method with 2 parameters and no return values. The parameters are of type http.ResponseWriter (an interface type) and *http.Request (a pointer type).

    So a call to a handler's ServeHTTP() involves 2 things: making a copy of its arguments - which is fast since they are small, and actually making the call (taking care of stack update like create a new stack frame, record return address, save used registers, and execute the called function) - which is also very fast (see quote at the end of the answer).

    So should you worry about calling functions? No. Will this be less performant compared to a handler which contains everything? Yes. Is the difference significant? No. Serving an HTTP request could take hundreds of milliseconds (network latency included). Calling 10 functions in your handler will not make it noticeably slower.

    If you'd worry about the performance loss due to function calls, then your app would consist of one single main() function. Obviously nobody wants that. You create functions to break down your initially large problem to smaller ones (recursively until it is "small enough" to be on its own) which you can oversee and reuse and test independently from others, and you assemble your large problem from the smaller ones. It's not really a question of performance but maintainability and reusability. Would you really want to copy that 100-line code which checks the user's identity to all your 10 different handlers?

    One last thing. Should you be concerned about "consuming" the stack (resulting in a stack overflow error)? The answer is no. A goroutine starts with a small 4096 byte stack which grows and shrinks as needed without the risk of ever running out. Read more about it at Why is a Goroutine’s stack infinite? Also detailed at FAQ: Why goroutines instead of threads?

    To make the stacks small, Go's run-time uses resizable, bounded stacks. A newly minted goroutine is given a few kilobytes, which is almost always enough. When it isn't, the run-time grows (and shrinks) the memory for storing the stack automatically, allowing many goroutines to live in a modest amount of memory. The CPU overhead averages about three cheap instructions per function call.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘