Why is html/template so slow?

agolangf · · 1191 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;ve asked this multiple times, hopefully will got better luck here. The original question was asked on StackOverflow, but received only one answer (not a bad one, but it didn&#39;t solve a problem). I won&#39;t reproduce it here (if anyone wants it code <a href="http://stackoverflow.com/questions/31361745/slow-performance-of-html-template-in-go-lang-any-workaround/31367138#31367138">here&#39;s the link</a>).</p> <p>The question is as stated in title. I&#39;ve created a blog page just to test go&#39;s templating engine, was stress testing it with loader.io. The page simply constructs an array of 100 items with one-line title and contents. Then, in a template, I {{ range }} over this data.</p> <p><a href="http://stackoverflow.com/questions/31361745/slow-performance-of-html-template-in-go-lang-any-workaround/31367138#31367138">Here&#39;s the code again</a>.</p> <p>Yes, I&#39;ve refined the code as proposed in an answer there, but that gave totally 0% gain in performance.</p> <p>I was impressed with how &#34;Hello World&#34; example beats other languages. But this one just went to the toilet. And it&#39;s so simple.</p> <p>Please don&#39;t tell this isn&#39;t a &#34;real-world-application-example-be-more-realistic-blah-blah&#34;. Come on, this is among most realistic examples of what the web pages are built on. I don&#39;t talk about raw inside performance here, but the simple output abilities of Go / html/template.</p> <p>I really liked Go and really want to find out any ways can I achieve great performance that Go does inside - on the outside!</p> <hr/>**评论:**<br/><br/>albatr0s: <pre><p>Doing</p> <pre><code>tmpl.Execute(w, p) </code></pre> <p>instead of</p> <pre><code>tmpl.ExecuteTemplate(w, &#34;index.html&#34;, p) </code></pre> <p>avoids a lock and makes the benchmark finish (in my case).</p></pre>uui83: <pre><p>I&#39;m already doing like that in all recent tests, no gain at all.</p></pre>albatr0s: <pre><p>I tested using <em>ab</em> and without that change the benchmarks didn&#39;t finish. After applying that change the test finished <em>most</em> of the times. I couldn&#39;t find the cause.</p></pre>pierrrre: <pre><p>html/template does escaping. The generated html code is safe. It&#39;s slower.</p> <p><a href="https://golang.org/pkg/html/template/">https://golang.org/pkg/html/template/</a></p></pre>uui83: <pre><p>I know, there are, as well, lots of PHP templating and &#34;fully secure&#34; libraries that produce the same result in terms of performance, not sure about security though. I wasn&#39;t into this kind of thing before, just wrote everything with straight htmlspecialchars() and so far everything was fine. Just discovered html/template has an ability to set a variable as known-safe through its&#39; type, though that doesn&#39;t work for me (don&#39;t know why), using text/template instead and escaping &#34;danger&#34; variables helps and keeps performance at least at PHP level.</p></pre>Mteigers: <pre><p>Most PHP renderers are also writing a cache. By time it hits a user large portions of it are static. </p></pre>funny_falcon: <pre><p>I found one compiled html template engine <a href="http://hackersome.com/p/mgutz/razor" rel="nofollow">http://hackersome.com/p/mgutz/razor</a> . Try it. It should be much faster.</p> <p>Other options to try <a href="https://github.com/avelino/awesome-go#template-engines" rel="nofollow">https://github.com/avelino/awesome-go#template-engines</a></p> <p><del>Other reason why php is fast: it renders html almost directly to socket (i.e. it doesn&#39;t buffer whole result by default).</del></p></pre>funny_falcon: <pre><p><a href="https://github.com/benbjohnson/ego" rel="nofollow">https://github.com/benbjohnson/ego</a></p></pre>no1youknowz: <pre><p>is there a way of doing the same with golang? that is not buffering the whole result?</p></pre>funny_falcon: <pre><p><a href="https://github.com/benbjohnson/ego" rel="nofollow">https://github.com/benbjohnson/ego</a> - try it.</p></pre>no1youknowz: <pre><blockquote> <p>Unlike other runtime-based templating languages, ego does not support ad hoc templates. All templates must be generated before compile time.</p> </blockquote> <p>This is the reason why I asked my question. I saw the other link. </p> <p>All my templates are dynamic.</p> <p>Don&#39;t presume next time.</p></pre>funny_falcon: <pre><p>Well, it looks like I am completely mistaken: Template.Execute accepts io.Writer, so that it writes to the socket.</p></pre>no1youknowz: <pre><p>Great, thanks for the confirmation.</p></pre>uui83: <pre><p>Thanks! Gonna test in a few hours.</p></pre>uui83: <pre><p><a href="https://github.com/sipin/gorazor" rel="nofollow">gorazor</a> totally rocks! I now can include real Go code in them as well. Though compiled templates makes an additional layer of time wasted on their compile process (sure this can be automated).</p> <p>Just <a href="https://loader.io/reports/f02cc395ac2373b8436e319c0184aa0e/results/531534cd6f5a9bf777ea05086d30a9a0" rel="nofollow">hit 160k</a> with them on my initial machine, now that&#39;s higher than PHP7. Great :)</p> <p>And for the upgraded machine (2 cores, 4 gb) the result <a href="http://ldr.io/1TDrl5R" rel="nofollow">hit 300k</a> with 90ms average. Later I noticed that was with 1 core only. &lt;- WOW.</p> <p>But to mention, nginx was automatically using 2 workers and they used almost one whole core, so I think it wouldn&#39;t be a good idea to use GOMAXPROCS=2 in this certain case.</p> <p>After PHP development &amp; deployment process here it will be a bit tougher, but might get used to it. Hopefully reflect and text/html/template packages will improve with time...</p> <p>BTW. After a few tests on Go, the app stays with 30-40% memory used and that isn&#39;t gonna be freed, why is it so? And how can I avoid situations when the process is killed because &#34;out of memory&#34; efficiently (e.g. I may try to stress test the app more hard in future).</p></pre>uui83: <pre><p>For more dramatic comparison. Upgraded test machine to 2 cores and 4 gb RAM. Tested on same &#34;blog&#34;. Results for PHP7: - 295k out of 300k successful responses over 1 min (5k cc/s), average latency 300ms</p> <p>Go (using GOMAXPROCS=2, and using text/template this time cause it fails to deliver with html/template): - 120k, average latency 4000ms</p> <p><strong>UPD.</strong> See my <a href="https://www.reddit.com/r/golang/comments/3d6j42/why_is_htmltemplate_so_slow/ct4s9oi" rel="nofollow">comment</a> after using compiled templates.</p></pre>no1youknowz: <pre><p>I would really like to see your go code. Just in case you are doing something wrong. I would have thought golang being much faster than php 7. </p> <p>Also how you are testing as well. ab, seige, etc?</p></pre>uui83: <pre><p>Loader.io, you can try it for free with up to 10k cc/s. <a href="http://pastebin.com/q6Ky4gt3" rel="nofollow">This is the Go code</a></p> <p>Golang is faster, when I don&#39;t output anything (don&#39;t use text/template).</p></pre>elithrar_: <pre><p>Just to add to my love of artificial benchmarking tools, I see 6.2k/req/s with GOMAXPROCS=4 and <code>html/template</code> with the example down-thread on an i7-4771, SSD, OS X. Available RAM inconsequential for this. Using <code>wrk -c 100 -d 5m -t 4 http://localhost:8888/</code> - external services can have a lot of variance.</p> <p>I can&#39;t test the PHP code as it only appears to be a snippet based on the <code>Route::</code> and <code>View::</code> classes.</p></pre>uui83: <pre><p>For the PHP results pretty much everything needed to be tuned, /etc/sysctl.conf, nginx workers and php-fpm.conf (ondemand 100 children, process_idle_timeout 5s and max_requests 5000). Then I&#39;ve discovered Go and here you go.</p> <p>I use DO droplets (they have good network) and so far testing different things for about a month with loader, there were no problems with the service at both ends. I didn&#39;t test with ab/wrk/siege cause I&#39;m on Windows and they work like broken here. But I&#39;ll try other machine later.</p></pre>elithrar_: <pre><p>Can I assume that nginx is caching responses that haven&#39;t changed? That&#39;s common behaviour (and Go can benefit from it as well).</p> <p>I also think that&#39;s the first time in your thread(s) that you&#39;ve mentioned the tuned nginx configuration. </p></pre>uui83: <pre><p>Yes, but nginx configuration is the one I use for about a month, it just uses auto workers and raises worker_rlimit_nofile (80k), as well as worker connections (40k). I didn&#39;t change anything about nginx for both Go and PHP (same goes for kernel).</p> <p>Of course I didn&#39;t cached anything from Go/PHP as well, that&#39;s just not right. You might want to see <a href="https://www.reddit.com/r/golang/comments/3d6j42/why_is_htmltemplate_so_slow/ct4s9oi" rel="nofollow">results with compiled templates</a>.</p> <p>If you need something from configurations, I can share, I test everything on a 512mb 1 core droplet and did a lot on tuning for past 1-2 months to get PHP work like a beast.</p></pre>iX6kNcrS: <pre><p>Just out of curiosity, what happens when $data[&#39;posts&#39;] is different every time.</p></pre>uui83: <pre><p>By the way, I&#39;ve tried mt_rand(0, 100000), it&#39;s the same. Without opcache, however, it&#39;s definitely slower (2x). But why on Earth would I switch opcache off...</p></pre>elithrar_: <pre><p>Out of curiosity: what does your PHP code look like? (i.e. post it, including mentions of any notable packages/templating libraries)</p></pre>uui83: <pre><p><a href="http://pastebin.com/fZXvnt7r" rel="nofollow">Here it is</a> No additional packages or templating engines, just a simple router and manual escaping of what I really need (perhaps in this case I don&#39;t even need it, added to test if things go bad).</p></pre>elithrar_: <pre><p>Although it may not be the root cause, there is a big difference between what PHP&#39;s <code>htmlspecialchars</code> does and what Go&#39;s <code>html/template</code> does - see here: <a href="http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition" rel="nofollow">http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition</a> (<a href="/u/pierrrre" rel="nofollow">/u/pierrrre</a> touched on this in another comment)</p></pre>uui83: <pre><p>Tl;dr, I trust the security model of this package but it seems a bit overwhelming, especially when I feel some data should be defined as known-safe. As for now, using text/template produces roughly the same result as PHP does (70k+, though tbh, latest PHP7 benchmarks raised its&#39; result up to 90k+ but that doesn&#39;t matter since it&#39;s already not those 5k for Go - probably there&#39;s some other, more lightweight way to fill this array like in PHP because at first sight, in Go, it was a bit hard for me to fill it without knowing the language, but building structs was a total fun).</p></pre>no1youknowz: <pre><p>Read, but didnt understand.</p> <p>Are you saying, that PHP 7 is faster than Golang?</p></pre>funny_falcon: <pre><p>He says that PHP 7 is faster than Golang when you need to render html without any other sophisticated work.</p> <p>To be more precise: he says that PHP7 (which is a huge and very optimized library for rendering unsafe html) is faster than Golang&#39;s standard library&#39;s package html/template, which is made to be simple to implement and simple and safe to use.</p> <p>With certain level of optimisation for concrete kind of task any language could be faster than other language, which is not optimized for concrete task.</p></pre>uui83: <pre><p>Yes I&#39;m talking about templates / rendering only.</p></pre>uui83: <pre><p>I tried to set Title, Content as template.HTML in my Post struct but everything seems the same. Is this a right way to explicitly set a variable as known-safe while still using html/template or I&#39;m doing it wrong again? ...</p></pre>TheMerovius: <pre><p>Yes, that&#39;s the right way</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1191 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传