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

时间:2016-10-05 09:05:08

标签: performance http go stack

我正在进行第一次生产web服务,所以我对语言和一些概念/模式都很陌生。

我的问题与处理程序有关,本质上是如何在不降低性能的情况下提取重复的代码。

我已经越过这个模式来包装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个堆栈帧。这是可以接受的还是会在流量很高时对性能产生负面影响?

1 个答案:

答案 0 :(得分:5)

链接中间件基本上只是让链条的处理程序调用下一个,通常基于条件是否一切顺利。或者在另一种方法中,一些外部机制可以逐个调用处理程序。

但是,所有事情都归结为处理程序将被调用。 Handler.ServeHTTP()方法如下所示:

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

一个带有2个参数且没有返回值的简单方法。参数的类型为http.ResponseWriter(接口类型)和*http.Request(指针类型)。

因此,对处理程序ServeHTTP()的调用涉及两件事:制作其参数的副本 - 这很快,因为它们很小,并实际进行调用(处理堆栈更新,如创建一个新的堆栈帧,记录返回地址,保存已使用的寄存器,并执行被调用的函数) - 这也非常快(参见答案末尾的引用)。

那你应该担心调用函数吗?不会。与包含所有内容的处理程序相比,这是否会降低性能?是。差异显着吗?否。提供H​​TTP请求可能需要数百毫秒(包括网络延迟)。在你的处理程序中调用10个函数不会明显变慢。

如果您担心因函数调用而导致性能下降,那么您的应用程序将包含一个main()函数。显然没有人想要那样。您可以创建函数来将最初的大问题分解为较小的问题(递归直到它为#34;足够小并且#34;独立),您可以监督重用< / em>和 test 独立于其他人,你汇总你的大问题。它不是性能问题,而是可维护性可重用性。您是否真的想要复制那些检查用户身份的100行代码给所有10个不同的处理程序?

最后一件事。你应该关注&#34;消费&#34;堆栈(导致堆栈溢出错误)?答案是不。 goroutine以一个小的4096字节堆栈开始,根据需要增长和缩小,而不会有用完的风险。请在Why is a Goroutine’s stack infinite?了解详情,详情请见FAQ: Why goroutines instead of threads?

  

为了使堆栈变小,Go的运行时使用可调整大小的有限堆栈。一个新的goroutine给了几千字节,这几乎总是足够的。当它不是时,运行时会增加(并缩小)用于自动存储堆栈的内存,允许许多goroutine存在于适量的内存中。 CPU开销平均每个函数调用大约三个廉价指令。