Templating libraries are a necessary a part of a programming language ecosystem. Go’s customary library offers highly effective templating libraries out of the field, however there are additionally a number of community-built templating libraries in Go for builders to make use of.
With a number of decisions obtainable, it may be troublesome to pick your best option on your specific use case.
This text will evaluate a few of the hottest templating libraries primarily based on efficiency, performance and safety, utilizing Go’s benchmarking device. Particularly, we are going to have a look at some frequent operations — like conditional operations, template nesting, and loops and so on. — utilized in templates and benchmark them to present you an thought of every template engine’s efficiency and reminiscence footprint.
I’ve determined to make use of 4 Go templating libraries as the idea of this text, primarily based on utilization and applicability to builders right now, as a number of others are both precompiled or sparsely maintained. The libraries we can be evaluating right now are template/textual content
, pongo2
, liquid
, and quicktemplate
.
Let’s get began!
template/textual content
Go’s customary library offers a fully-featured and highly effective templating engine. It is extremely performant and nicely optimized.
Efficiency
Efficiency is most necessary side of any pc program. Go’s customary is extensively utilized in manufacturing, and is understandably a well-liked choice for builders.
Parsing
in case your use case requires templates to vary ceaselessly, or it’s worthwhile to load templates on each request, then parsing shortly turns into a vital benchmark. The textual content
bundle offers varied parsing strategies; like parsing from string, file, or utilizing sample to learn to recordsdata from a filesystem.
// template has loop, if assertion perform name and so on.
BenchmarkGoParsing-10 32030 37202 ns/op
You may parse the template on startup and cache it to enhance efficiency. In case your template adjustments ceaselessly, then you need to use a cron, which replace at a set interval of time within the background.
String substitution
A string substitution is most elementary perform of any templating engine, and textual content
is tremendous quick in string substitution.
// template -> This can be a easy string {{ .Title }} with worth as string
BenchmarkGoStd-10 4185343 288.8 ns/op
String substitution is quicker when utilizing struct as information context — utilizing map may be a bit sluggish, because it additionally will increase the time taken for key lookup.
// template -> This can be a easy string {{ index . "identify" }} with worth as string
BenchmarkGoStdMapWithIndex-10 1333495 852.7 ns/op
As you may see utilizing map is expensive. Avoiding index
perform enable to optimise above template.
// template -> This can be a easy string {{ .Title }} with worth as string`
BenchmarkGoStdMapWith-10 3563234 338.5 ns/op
.
additionally permits us to carry out a key lookup on map.
Conditionals
Conditionals are an important operation for template engines; inefficient conditional operations lead to dangerous efficiency. The textual content
bundle offers help for if
operations, with help for and
and or
operations. Each of those take a number of arguments the place every argument is a boolean kind. textual content
offers cheap efficiency for conditionals.
// template -> That is the file {{if and .First (eq .Second "worth") (ne .Third "worth")}}Obtained{{finish}}. Git do
BenchmarkGoIfString-10 506409 2323 ns/op
The efficiency demonstrated above might be improved by avoiding eq
and ne
calls. Each perform in template
known as through reflection, inflicting a efficiency hit right here.
If eq .Second
"``worth``"
was within the code, then the compiler would be capable of optimize it, for the reason that concrete kind can be identified on the compiler kind. If all eq
and ne
calls are changed by a easy boolean, speeds can be quicker.
// template -> That is the file {{if and .First .4 .5}}Obtained{{finish}}. Git do
BenchmarkGoIf-10 987169 1186 ns/op
(Notice: Throughout benchmarking, string comparisons have been additionally included in time computations)
Extra nice articles from LogRocket:
Loops
Loops are additionally supplied by textual content
bundle. vary
is used to iterate over slices, arrays, and maps. Efficiency for loops will depend on the operations contained in loop physique.
// template ->`{{vary .Six}}{{.}},{{finish}}`
BenchmarkGoLoop-10 1283661 919.8 ns/op
Equally, iterating over map can be performant:
// template -> {{vary $key, $worth:=.Seven}}{{$key}},{{$worth}}:{{finish}}
BenchmarkGoLoopMap-10 566796 2003 ns/op
Operate calls
Operate calls as a substitute enable developer to vary and rework inputs inside a template. However, this usually incurs a price, for the reason that perform calls occur through reflection. Utilizing capabilities has a excessive overhead value — if attainable, keep away from perform calls.
// template -> This can be a easy string {{ noop }} with worth as string
BenchmarkGoStdCallFunc-10 2611596 472.3 ns/op
Nested templates
Nested templates enable customers to share code and keep away from repeating code unnecessarily. textual content
offers help for calling nested templates.
// template -> {{outline "noop"}} That is {{.Second}} and {{.Third}} {{finish}}
//
//{{template "noop" .}}
BenchmarkGoNested-10 1868461 630.2 ns/op
It’s value noting that textual content
specifically has glorious neighborhood help, with libraries like sprig
offering a variety of capabilities that can be utilized inside a template. Help for syntax highlighting and validation built-in comes as customary with Go’s customary library templating bundle.
pongo2
pongo2
is a community-built template engine with syntax impressed by Django-syntax. It’s constructed by the neighborhood for Go. It is extremely in style right now, with greater than 2K stars on GitHub.
Efficiency
pongo2
is nicely optimized for perform calls inside templates. It’s a full template engine with loops, conditionals, and nested templates.
Parsing
pongo2
helps parsing templates from string, byte, recordsdata, and cache. We will see, performance-wise, it’s a bit quicker than Go’s customary library’s template bundle:
// template has loop, if, nested template and performance name
BenchmarkPongoParsing-10 38670 29153 ns/op
String substitution
String substitution is bit slower in pongo2
when put next with the textual content
bundle. It solely helps map for information context, leading to further lookup operation time, which is mirrored within the following benchmark.
// template -> This can be a easy string {{ identify }} with worth as string
BenchmarkPongo2-10 1815843 654.2 ns/op
Conditionals
pongo2
has extra developer pleasant syntax for if/else. It’s nearer to how if/else are written in programming languages. if/else
is extra pricey from a efficiency standpoint in pongo2 than the textual content
bundle.
// template -> Title is {% if First && 4 && 5 %}received{% endif %}. Go
BenchmarkPongo2String2If-10 709471 1528 ns/op
Loops
Loops in pongo2
are a bit slower than textual content
bundle:
// template -> {% for worth in Six %} {{ worth }}, {% endfor %}
BenchmarkPongo2String2Loop-10 650672 1796 ns/op
Loops on map are additionally slower:
// template -> {% for key,worth in Seven %} {{key}},{{ worth }}, {% endfor %}
BenchmarkPongo2String2LoopMap-10 359858 3182 ns/op
Operate calls
Operate calls are quicker in pongo2
than the textual content
bundle, because it has a perform signature identified at compile time, and performance doesn’t have to undergo a mirrored image name, making it quicker.
// template -> This can be a easy string {{ noop }} with worth as string
BenchmarkPongo2StdCallFunc-10 4775058 261.9 ns/op
Nested templates
pongo2
macros are supplied for nested template efficiency, that are slower than the textual content
bundle.
// template -> {% macro noop(first, second) %}
That is {{first}} and {{second}}
{% endmacro %}
{{noop("anshul","goyal")}}
BenchmarkPongo2String2Nested-10 657597 1665 ns/op
liquid
liquid
is a community-built implementation of Shopify’s template language. It offers a totally featured templating library.
Efficiency
liquid
is sort of performant from my analysis. It’s a full template engine with loops, conditionals, and nested templates.
Parsing
liquid
helps parsing templates from string, byte, and recordsdata. When it comes to efficiency, it’s a bit slower than Go’s customary library template bundle and pongo2
.
// template has loop, if, nested template and performance name
BenchmarkLiquidParsing-10 29710 40114 ns/op
String substitution
String substitution efficiency is comparable with pongo2
, whereas liquid
is a bit slower than the textual content
bundle. It solely helps map for information context, leading to further lookup operation time, proven in following benchmark.
// template -> This can be a easy string {{ identify }} with worth as string
BenchmarkLiquidString-10 1815843 676.0 ns/op
Conditionals
liquid
has very developer pleasant syntax for if/else. It’s nearer to how if/else are written in different established programming languages. if/else
is much less performant in liquid than the textual content
bundle, however quicker than pongo2
.
// template -> That is the file {%if First and 4 and 5 %}Obtained{%endif%}. Git do
BenchmarkLiquidIf-10 709471 953.3 ns/op
Loops
Loops in liquid
are additionally slower than when utilizing the textual content
bundle. Loops are slower in liquid
even when put next with pongo2
:
// template -> {%for worth in Six %}{{worth}},{%endfor%}
BenchmarkLiquidLoop-10 650672 3067 ns/op
Operate calls
Operate calls are quicker in pongo2
than liquid
, because it has a perform signature pulled at compile time and performance doesn’t have to undergo a mirrored image name, making it quicker.
// template -> This can be a easy string {{ noop }} with worth as string
BenchmarkPongo2StdCallFunc-10 4775058 359.0 ns/op
quicktemplate
quicktemplate
is a precompiled template; it converts templates into Go code. It doesn’t enable builders to vary code at runtime. quicktemplate
may be very quick as it’s doesn’t carry out any reflection and every little thing is run by a compiler optimizer.
In case your use case don’t want frequent updates, then quicktemplate
may be excellent selection for you. Benchmarks for quicktemplate
compared to liquid
and fasttemplate
(for string substitutions) are proven beneath:
Characteristic | liquid | fasttemplate | quicktemplate |
---|---|---|---|
Parsing | 40114 ns/op | 188.8 ns/op | N/A |
If statements | 953.3 ns/op | N/A | 87.47 ns/op |
if statements with strings | 1144 ns/op | N/A | 99.18 ns/op |
loops | 3067 ns/op | N/A | 268.8 ns/op |
capabilities | 359.0 ns/op | N/A | 191.7 ns/op |
nested templates | N/A | N/A | 191.7 ns/op |
String Substitution | 676.0 ns/op | 75.21 ns/op | 105.9 ns/op |
quicktemplate
is pre-compiled template engine (i.e. a template is transformed to Go code). The Go code is then optimized by the compiler, leading to very quick execution. It additionally avoids reflection, leading to large efficiency positive factors.
(Notice: quicktemplate
offers quick template execution, however at the price of no runtime updates of the template. fasttemplate
solely helps string substitution)
Conclusion
pongo2
and textual content
each have their very own execs and cons. pongo2
presents a bit extra developer pleasant syntax than textual content
, however textual content
offers higher efficiency general.
Which templating library you employ all will depend on which fits your wants higher for a specific challenge. textual content
comes pre-bundled with Go’s set up, making it naturally a very talked-about selection, whereas choices like quicktemplate
may also be a good selection in case your templates don’t must be modified ceaselessly, and others like pongo2
are simpler to make use of should you don’t a lot get pleasure from utilizing Go’s customary library. When you solely require string substitution, then fasttemplate
can be an awesome selection from a efficiency perspective.