我正在为一个网站编写一个基本的服务器。现在我面临一个(对我来说)困难的性能问题。在init()
函数中读取模板文件是否更好?
// Initialize all pages of website
func init(){
indexPageData, err := ioutil.ReadFile("./tpl/index.tpl")
check(err)
}
字符串
在http.HandlerFunc
?
func index(w http.ResponseWriter, req *http.Request){
indexPageData, err := ioutil.ReadFile("./tpl/index.tpl")
check(err)
indexPageTpl := template.Must(template.New("index").Parse(string(indexPageData)))
indexPageTpl.Execute(w, "test")
}
型
我认为在第一个例子中,在服务器启动后,您不需要访问磁盘并提高请求的性能。
但在开发过程中,我想刷新浏览器并查看新内容。这可以通过第二个示例完成。
有人有最先进的解决方案吗?或者从性能的Angular 来看,什么是正确的?
3条答案
按热度按时间hrysbysz1#
下面我们来分析一下性能:
我们将您的第一个解决方案命名为a(稍有改动,请参见下文),将您的第二个解决方案命名为b。
一个请求:
a:一个磁盘访问
B:一个磁盘访问
十项请求:
a:一个磁盘访问
B:10次磁盘访问
1000万宗要求:
a:一个磁盘访问
B:10 000 000次磁盘访问(这很慢)
因此,您的第一个解决方案的性能更好。但是,您对最新数据的担忧是什么呢?从
func (t *Template) Execute(wr io.Writer, data interface{}) error
的文档可以看出:Execute会将剖析过的样板套用至指定的数据对象,并将输出写入wr。如果在执行样板或写入其输出时发生错误,则会停止执行,但部分结果可能已写入输出写入器。样板可以安全地平行执行。
所以,事情是这样的:
1.您从磁盘读取模板
1.将文件解析为模板
1.您可以选择要 * 填入空白 * 的数据
1.使用该数据对模板进行
Execute
,结果将写入io.Writer
您选择的数据是最新的。这与从磁盘重新读取模板,甚至重新解析模板无关。这就是模板背后的全部理念:一次磁盘访问,一次解析,多个动态最终结果。
上面引用的文档告诉我们另一件事:
可以安全地并行执行模板。
这非常有用,因为如果您有多个并行请求,则
http.HandlerFunc
是并行运行得.那么,现在该怎么办呢?
Read
模板文件一次,Parse
模板一次,Execute
每个请求的模板 *。我不确定你是否应该在
init()
函数中读取和解析,因为至少Must
可能会死机(不要在那里使用一些相对的硬编码路径!)--我会尝试在一个更可控的环境中这样做,例如,提供一个函数(如New()
)来创建一个新的服务器示例,并在那里执行这些操作。编辑:我重新阅读了您的问题,可能误解了您的意思:
如果模板本身仍在开发中,则是的,您必须在每次请求时读取它以获得最新的结果。这比每次更改模板时重新启动服务器更方便。对于生产,模板应是固定的,并且只应更改数据。
如果我理解错了,我很抱歉。
icomxhvb2#
永远不要在生产中读取和解析请求处理程序中的模板文件,这是最糟糕的(你应该总是避免这种情况)。
阅读此问题以了解更多详情:
It takes too much time when using "template" package to generate a dynamic web page to client in golang
你可以用多种方法来实现这一点。这里我列出了4个例子。
1.设置为“dev mode”
你可以有一个常量或变量来告诉你是否在开发模式下运行,这意味着模板不会被缓存。
这里有一个例子:
字符串
2.在请求中指定(作为参数)是否需要新模板
当你开发时,你可以指定一个额外的URL参数,指示读取一个新的模板,而不是使用缓存的模板,例如
http://localhost:8080/index?dev=true
示例实现:
型
3.根据主机决定
您也可以检查请求URL的主机名,如果是
"localhost"
,您可以忽略该高速缓存并使用新的模板。这需要最小的额外代码和工作。请注意,您可能还想接受其他主机,例如"127.0.0.1"
(取决于您想要包含的内容)。示例实现:
型
4.检查模板文件最后一次修改
您也可以在加载模板文件时存储模板文件的最后修改时间。每当请求模板时,您可以检查源模板文件的最后修改时间。如果它已更改,您可以在执行之前重新加载它。
示例实现:
型
w8biq8rn3#
考虑更好,所以证明它(使用基准)
Iterations
=(越大越好)ns/op
=每次操作的时间(越少越好)B/op
=每个操作分配的内存(越少越好)allocs/op
=每个操作的分配(越少越好)第四名(最慢访问和最高内存)
字符串
第三名(访问速度更快,内存比前一个少一点)
型
第二名(访问速度更快,内存更小)
型
第二名(访问速度慢,内存比前一名少)
型
第一名(访问速度最快,内存最小)
型