将HTTP响应写入临时bytes.Buffer [英] Writing HTTP responses to a temporary bytes.Buffer
问题描述
为了优化写入临时 bytes.Buffer
以捕获模板中的任何错误,我一直在进行一些分析和基准测试。 ExecuteTemplate
。
具体来说,我们正在写入缓冲区,检查是否有错误,如果没有,写入 http.ResponseWriter
。然而,问题在于临时缓冲区的请求开销有些显着: b
$ b
当然,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: [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 Specifically, we're writing to the buffer, checking for any errors, and if none, writing out to our Of course, 21k req/s is still a lot of requests, but a 22% perf. hit is also a fairly large impact. 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:
[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屋!
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
bytes.Buffer
to catch any errors from template.ExecuteTemplate
.http.ResponseWriter
. The problem, however, is that the temporary buffer has a request overhead that's somewhat noticeable:
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
}
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)
}