将HTTP响应写入临时bytes.Buffer [英] Writing HTTP responses to a temporary bytes.Buffer

查看:154
本文介绍了将HTTP响应写入临时bytes.Buffer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了优化写入临时 bytes.Buffer 以捕获模板中的任何错误,我一直在进行一些分析和基准测试。 ExecuteTemplate



具体来说,我们正在写入缓冲区,检查是否有错误,如果没有,写入 http.ResponseWriter 。然而,问题在于临时缓冲区的请求开销有些显着: b
$ b


  • 约6.2k req / s - 27.6k - > 21.4k,配置为29k - > 24k;
  • 每请求延迟9ms(40ms - > 49ms)。


当然,21k req / s仍然是很多请求,但是会有22%的性能。命中也是一个相当大的影响。

  func renderTemplate(w http.ResponseWriter,name string,data map [string] interface { })错误{
//确保模板存在于地图中。
tmpl,ok:= templates [name]
if!ok {
return ErrTemplateDoesNotExist
}

//创建一个临时写入的缓冲区检查是否遇到任何错误。
buf:= bytes.NewBuffer(make([] byte,0,10000))
err:= tmpl.ExecuteTemplate(buf,base,data)
if err!= nil {
return err
}

//设置标题并将缓冲区写入http.ResponseWriter
w.Header()。Set(Content-Type ,text / html; charset = utf-8)
buf.WriteTo(w)

return nil
}

10K缓冲区大小是对我的响应中大多数最典型的最大页面大小的粗略估计,尽管我还没有以测试这超出了一小撮页面。大于缓冲区大小的响应通常会导致性能再增加20%。

是否有更好的方法在中写入临时缓冲区?每个请求?另一位gopher指出即将推出的 sync.Pool 在Go 1.3中,但我不知道从哪里开始写出来。






新增:使用 http://godoc.org/github.com/oxtoacart/bpool 目前在每个请求36ms产生33k req / s:

  var bufpool * bpool.BufferPool 

func renderTemplate(w http.ResponseWriter,name string,data map [string] interface {})error {
...
buf:= bufpool.Get()
err := tmpl.ExecuteTemplate(buf,base,data)
if err!= nil {
return err
}

//设置标题并写入bu转到http.ResponseWriter
w.Header()。Set(Content-Type,text / html; (b)



$ func init(){
bufpool = bpool.NewBufferPool(48)

}


解决方案

[b
$ b

只需使用可用的池而不是标准池图书馆,这看起来像它会工作(搜索godoc一些其他的选择):



http://godoc.org/github.com/oxtoacart/bpool



你可能应该不管大小如何,只要减少垃圾收集器的压力,也可以看到吞吐量的增加。


I've been doing some profiling and benchmarking in order to optimise writing out to a temporary bytes.Buffer to catch any errors from template.ExecuteTemplate.

Specifically, we're writing to the buffer, checking for any errors, and if none, writing out to our http.ResponseWriter. The problem, however, is that the temporary buffer has a request overhead that's somewhat noticeable:

  • About 6.2k req/s - 27.6k -> 21.4k with profiling on, and 29k -> 24k with it off;
  • A 9ms (40ms -> 49ms) increase in per request latency.

Of course, 21k req/s is still a lot of requests, but a 22% perf. hit is also a fairly large impact.

func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
    // Ensure the template exists in the map.
    tmpl, ok := templates[name]
    if !ok {
        return ErrTemplateDoesNotExist
    }

    // Create a buffer to temporarily write to and check if any errors were encountered.
    buf := bytes.NewBuffer(make([]byte, 0, 10000))
    err := tmpl.ExecuteTemplate(buf, "base", data)
    if err != nil {
        return err
    }

    // Set the header and write the buffer to the http.ResponseWriter
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
        buf.WriteTo(w)

    return nil
}

The 10K buffer size is a rough estimation of the typical max page size of most of my responses, although I've yet to test this beyond a small handful of pages just yet. A response larger than the buffer size typically results in another 20% hit to performance.

Is there a better way to write to a temporary buffer in every request? Another gopher pointed out the upcoming sync.Pool in Go 1.3, but I'm not sure where to start when it comes to writing that out.


Added: using http://godoc.org/github.com/oxtoacart/bpool at the moment yields 33k req/s at 36ms per request:

var bufpool *bpool.BufferPool

func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
    ...
    buf := bufpool.Get()
    err := tmpl.ExecuteTemplate(buf, "base", data)
    if err != nil {
        return err
    }

    // Set the header and write the buffer to the http.ResponseWriter
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    buf.WriteTo(w)
    bufpool.Put(buf)

    return nil
}

func init() {
    bufpool = bpool.NewBufferPool(48)

}

解决方案

[copied from comments as an answer]

Just pool your buffers using an available pool not from the standard library. This one looks like it will work (search godoc a bit for a few other alternatives):

http://godoc.org/github.com/oxtoacart/bpool

Yyou should probably also see an increase in throughput regardless of size, just by reducing the garbage collector pressure.

这篇关于将HTTP响应写入临时bytes.Buffer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆