Why is it astonishingly slow?
I've benchmarked this project versus Shopify/liquid on Ruby 2.5 And got very strange results:
Ruby
tpl = Liquid::Template.parse(template)
ctx = Liquid::Context.new
ctx["order"] = order
Benchmark.ips do |x|
x.report("parse & render") {
ctx = Liquid::Context.new
ctx["order"] = order
Liquid::Template.parse(template).render(ctx)
}
x.report("render") {
tpl.render(ctx)
}
end
Crystal
tpl = Liquid::Template.parse(template)
ctx = Liquid::Context.new
ctx.set("order", order)
Benchmark.ips do |x|
x.report("parse & render") {
ctx = Liquid::Context.new
ctx.set("order", order)
Liquid::Template.parse(template).render(ctx)
}
x.report("render") { tpl.render(ctx) }
end
Ruby (template without filters)
parse & render 2.698k (± 3.8%) i/s - 13.585k in 5.042274s
render 10.020k (± 2.6%) i/s - 50.085k in 5.002127s
Crystal (template without filters)
parse & render 1.56k (639.72µs) (± 2.02%) 171kB/op 2.52× slower
render 3.94k (253.49µs) (± 1.97%) 73.9kB/op fastest
Ruby (template with one strip_newlines filter)
parse & render 2.547k (± 3.3%) i/s - 12.760k in 5.014887s
render 8.649k (± 4.6%) i/s - 43.962k in 5.094069s
Crystal (template with one strip_newlines filter)
parse & render 1.50k (667.40µs) (± 1.20%) 179kB/op fastest
render 1.29k (776.84µs) (±57.11%) 235kB/op 1.16× slower
Crystal version was built with --release flag, but it didn't help. As you can see, Liquid on Crystal renders in 2.5 slower than on Ruby in the best case (without any filters). Using Liquid-filters kills performance of rendering on Crystal completely. And surprisingly just render starts to take more time than parse + render.
P.S. Here is the test data
The issue seems to be in the for loop.
render w/o for 22.06k ( 45.32µs) (±10.62%) 5.9kB/op fastest
render with for 2.34k (428.26µs) (± 9.74%) 68.3kB/op 9.45× slower
@TechMagister Well, now we know that using for & filters in a template kills rendering performance... But they both are essential parts of Liquid.
Why can't we port code from ruby version instead of reinventing a slow wheel?
@romul We can port code, but I have no time for this for the moment :/