💨 Writing Fast Crystal 😍 -- Collect Common Crystal idioms.
It's Crystal version based on ruby version.
Each idiom has a corresponding code example that resides in code.
All results listed in README.md are running with Crystal 0.25.0 (2018-06-15) LLVM 5.0.1 on OS X 10.13.5.
Machine information: MacBook Pro (Retina, 15-inch, Mid 2015), 2.2 GHz Intel Core i7, 16 GB 1600 MHz DDR3.
Your results may vary, but you get the idea. : )
Doubt the results? please discuss in Crystal Issue#4383.
Let's write faster code, together! :trollface:
Use Crystal's built-in benchmark.
$ make
require "benchmark"def fast end
def slow end
Benchmark.ips do |x| x.report("fast code description") { fast } x.report("slow code description") { slow } end
Test in Crystal 0.35.1 (2020-06-19) LLVM: 10.0.0 Default target: x86_64-apple-macosx
firstvs
index[0]code
$ crystal build --release --no-debug -o bin/code/array/first-vs-index[0] code/array/first-vs-index[0].cr $ ./bin/code/array/first-vs-index[0]Array#first 265.31M ( 3.77ns) (±11.17%) 0.0B/op 1.01× slower Array#[0] 267.85M ( 3.73ns) (± 6.86%) 0.0B/op fastest
insertvs
unshiftcode
$ crystal build --release --no-debug -o bin/code/array/insert-vs-unshift code/array/insert-vs-unshift.cr $ ./bin/code/array/insert-vs-unshiftArray#insert 1.30 (768.66ms) (± 1.33%) 1.5MB/op fastest Array#unshift 1.29 (775.05ms) (± 1.81%) 1.5MB/op 1.01× slower
lastvs
index[-1]code
$ crystal build --release --no-debug -o bin/code/array/last-vs-index[-1] code/array/last-vs-index[-1].cr $ ./bin/code/array/last-vs-index[-1]Array#[-1] 273.97M ( 3.65ns) (± 4.16%) 0.0B/op fastest Array#last 273.61M ( 3.65ns) (± 4.75%) 0.0B/op 1.00× slower
rangevs
times.mapcode
$ crystal build --release --no-debug -o bin/code/array/range-vs-times.map code/array/range-vs-times.map.cr $ ./bin/code/array/range-vs-times.mapRange#to_a 1.11M (897.91ns) (±17.84%) 1.67kB/op fastest Times#to_a 1.02M (980.17ns) (±17.56%) 1.69kB/op 1.09× slower
each pushvs
mapcode
$ crystal build --release --no-debug -o bin/code/enumerable/each-push-vs-map code/enumerable/each-push-vs-map.cr $ ./bin/code/enumerable/each-push-vs-mapArray#map 507.91k ( 1.97µs) (±11.92%) 3.96kB/op fastest Array#each + push 145.04k ( 6.89µs) (±18.89%) 12.7kB/op 3.50× slower
Array#each_with_object 155.85k ( 6.42µs) (±17.07%) 12.7kB/op 3.26× slower
eachvs
loopcode
$ crystal build --release --no-debug -o bin/code/enumerable/each-vs-loop code/enumerable/each-vs-loop.cr $ ./bin/code/enumerable/each-vs-loopWhile Loop 1.64M (609.64ns) (± 7.66%) 0.0B/op 159.20× slower #each 261.15M ( 3.83ns) (±10.82%) 0.0B/op fastest
each_with_indexvs
while loopcode
$ crystal build --release --no-debug -o bin/code/enumerable/each_with_index-vs-while-loop code/enumerable/each_with_index-vs-while-loop.cr $ ./bin/code/enumerable/each_with_index-vs-while-loopWhile Loop 1.51M (661.13ns) (± 9.29%) 0.0B/op 6.94× slower
each_with_index 10.50M ( 95.23ns) (±17.95%) 0.0B/op fastest
map flattenvs
flat_mapcode
$ crystal build --release --no-debug -o bin/code/enumerable/map-flatten-vs-flat_map code/enumerable/map-flatten-vs-flat_map.cr $ ./bin/code/enumerable/map-flatten-vs-flat_mapArray#flat_map (Tuple) 902.86k ( 1.11µs) (± 6.63%) 3.65kB/op fastest Array#map.flatten (Tuple) 664.00k ( 1.51µs) (± 6.00%) 4.69kB/op 1.36× slower Array#flat_map (Array) 238.37k ( 4.20µs) (± 5.73%) 7.18kB/op 3.79× slower Array#map.flatten (Array) 193.64k ( 5.16µs) (± 3.78%) 9.39kB/op 4.66× slower
reverse.eachvs
reverse_eachcode
$ crystal build --release --no-debug -o bin/code/enumerable/reverse.each-vs-reverse_each code/enumerable/reverse.each-vs-reverse_each.cr $ ./bin/code/enumerable/reverse.each-vs-reverse_eachArray#reverse.each 4.03M (248.39ns) (± 5.02%) 480B/op 4.94× slower Array#reverse_each 19.88M ( 50.30ns) (± 2.49%) 0.0B/op fastest
sortvs
sort_bycode
$ crystal build --release --no-debug -o bin/code/enumerable/sort-vs-sort_by code/enumerable/sort-vs-sort_by.cr $ ./bin/code/enumerable/sort-vs-sort_byEnumerable#sort 145.32k ( 6.88µs) (± 2.89%) 3.07kB/op 1.17× slower Enumerable#sort_by 170.71k ( 5.86µs) (± 4.47%) 1.04kB/op fastest
$ crystal build --release --no-debug -o bin/code/general/assignment code/general/assignment.cr $ ./bin/code/general/assignmentSequential Assignment 611.21M ( 1.64ns) (± 4.98%) 0.0B/op 1.00× slower Parallel Assignment 613.61M ( 1.63ns) (± 5.04%) 0.0B/op fastest
hashvs
structvs
namedtuplecode
$ crystal build --release --no-debug -o bin/code/general/hash-vs-struct-vs-namedtuple code/general/hash-vs-struct-vs-namedtuple.cr $ ./bin/code/general/hash-vs-struct-vs-namedtupleNamedTuple 515.36M ( 1.94ns) (± 4.05%) 0.0B/op fastest Struct 503.85M ( 1.98ns) (± 6.54%) 0.0B/op 1.02× slower Hash 9.60M (104.18ns) (± 2.76%) 208B/op 53.69× slower
loopvs
while_truecode
$ crystal build --release --no-debug -o bin/code/general/loop-vs-while_true code/general/loop-vs-while_true.cr $ ./bin/code/general/loop-vs-while_trueWhile Loop 512.11M ( 1.95ns) (± 5.15%) 0.0B/op fastest Kernel Loop 482.98M ( 2.07ns) (±16.94%) 0.0B/op 1.06× slower
positional_argumentvs
named_argumentcode
$ crystal build --release --no-debug -o bin/code/general/positional_argument-vs-named_argument code/general/positional_argument-vs-named_argument.cr $ ./bin/code/general/positional_argument-vs-named_argumentNamed arguments 564.18M ( 1.77ns) (±16.11%) 0.0B/op 1.03× slower
Positional arguments 578.90M ( 1.73ns) (±10.46%) 0.0B/op fastest
propertyvs
getter_and_settercode
$ crystal build --release --no-debug -o bin/code/general/property-vs-getter_and_setter code/general/property-vs-getter_and_setter.cr $ ./bin/code/general/property-vs-getter_and_setterproperty 50.89M ( 19.65ns) (± 5.34%) 32.0B/op fastest
getter_and_setter 49.68M ( 20.13ns) (± 7.27%) 32.0B/op 1.02× slower
[]?vs
has_key?code
$ crystal build --release --no-debug -o bin/code/hash/[]?-vs-has_key? code/hash/[]?-vs-has_key?.cr $ ./bin/code/hash/[]?-vs-has_key?Hash#[]? 41.12M ( 24.32ns) (±12.09%) 0.0B/op 1.01× slower
Hash#has_key? 41.48M ( 24.11ns) (± 8.25%) 0.0B/op fastest
bracketvs
fetchcode
$ crystal build --release --no-debug -o bin/code/hash/bracket-vs-fetch code/hash/bracket-vs-fetch.cr $ ./bin/code/hash/bracket-vs-fetchHash#[] 95.60M ( 10.46ns) (± 6.16%) 0.0B/op 1.02× slower Hash#fetch 97.08M ( 10.30ns) (± 9.36%) 0.0B/op fastest
clonevs
dupcode
$ crystal build --release --no-debug -o bin/code/hash/clone-vs-dup code/hash/clone-vs-dup.cr $ ./bin/code/hash/clone-vs-dupHash#dup 5.39M (185.50ns) (±17.96%) 480B/op fastest Hash#clone 293.35k ( 3.41µs) (±10.17%) 5.94kB/op 18.38× slower
keys eachvs
each_keycode
$ crystal build --release --no-debug -o bin/code/hash/keys-each-vs-each_key code/hash/keys-each-vs-each_key.cr $ ./bin/code/hash/keys-each-vs-each_keyHash#keys.each 4.25M (235.11ns) (± 8.09%) 240B/op 1.11× slower Hash#each_key 4.71M (212.43ns) (±22.16%) 160B/op fastest
merge bangvs
[]=code
$ crystal build --release --no-debug -o bin/code/hash/merge-bang-vs-[]= code/hash/merge-bang-vs-[]=.cr $ ./bin/code/hash/merge-bang-vs-[]=Hash#merge! 67.40k ( 14.84µs) (±23.77%) 16.6kB/op 4.19× slower Hash#[]= 282.73k ( 3.54µs) (±21.37%) 4.14kB/op fastest
bracketvs
fetchcode
$ crystal build --release --no-debug -o bin/code/namedtuple/bracket-vs-fetch code/namedtuple/bracket-vs-fetch.cr $ ./bin/code/namedtuple/bracket-vs-fetchNamedTuple#[] 294.37M ( 3.40ns) (±19.52%) 0.0B/op 1.00× slower NamedTuple#fetch 295.49M ( 3.38ns) (±19.80%) 0.0B/op fastest
fetchvs
fetch_with_blockcode
$ crystal build --release --no-debug -o bin/code/namedtuple/fetch-vs-fetch_with_block code/namedtuple/fetch-vs-fetch_with_block.cr $ ./bin/code/namedtuple/fetch-vs-fetch_with_blockNamedTuple#fetch + const 168.24M ( 5.94ns) (± 6.53%) 0.0B/op 1.81× slower NamedTuple#fetch + block 304.53M ( 3.28ns) (± 4.50%) 0.0B/op fastest NamedTuple#fetch + arg 296.07M ( 3.38ns) (± 6.99%) 0.0B/op 1.03× slower
blockvs
to_proccode
$ crystal build --release --no-debug -o bin/code/proc-and-block/block-vs-to_proc code/proc-and-block/block-vs-to_proc.cr $ ./bin/code/proc-and-block/block-vs-to_procBlock 331.06k ( 3.02µs) (±13.18%) 2.6kB/op 1.10× slower
Symbol#to_proc 362.78k ( 2.76µs) (± 5.27%) 2.6kB/op fastest
proc callvs
yieldcode
$ crystal build --release --no-debug -o bin/code/proc-and-block/proc-call-vs-yield code/proc-and-block/proc-call-vs-yield.cr $ ./bin/code/proc-and-block/proc-call-vs-yieldblock.call 513.72M ( 1.95ns) (± 4.51%) 0.0B/op fastest
block + yield 501.67M ( 1.99ns) (± 7.25%) 0.0B/op 1.02× slower block argument 512.94M ( 1.95ns) (± 5.41%) 0.0B/op 1.00× slower yield 482.96M ( 2.07ns) (±15.43%) 0.0B/op 1.06× slower
$ crystal build --release --no-debug -o bin/code/string/concatenation code/string/concatenation.cr $ ./bin/code/string/concatenationString#+ 44.62M ( 22.41ns) (± 8.00%) 32.0B/op fastest String#{} 23.68M ( 42.22ns) (±16.74%) 32.0B/op 1.88× slower String#% 4.28M (233.43ns) (±20.03%) 176B/op 10.41× slower
ends string-matching-matchvs
end_withcode
$ crystal build --release --no-debug -o bin/code/string/ends-string-matching-match-vs-end_with code/string/ends-string-matching-match-vs-end_with.cr $ ./bin/code/string/ends-string-matching-match-vs-end_withString#end_with? 238.71M ( 4.19ns) (±11.61%) 0.0B/op fastest String#=~ 7.93M (126.04ns) (± 4.61%) 16.0B/op 30.09× slower
$ crystal build --release --no-debug -o bin/code/string/equal-substring-of-char code/string/equal-substring-of-char.cr $ ./bin/code/string/equal-substring-of-char"==="[0] == '=' 298.29M ( 3.35ns) (± 7.06%) 0.0B/op fastest "==="[0].to_s == "=" 23.29M ( 42.94ns) (± 6.52%) 48.0B/op 12.81× slower
"==="[0] == "=".chars[0] 27.62M ( 36.21ns) (± 4.66%) 48.0B/op 10.80× slower
equalvs
matchcode
$ crystal build --release --no-debug -o bin/code/string/equal-vs-match code/string/equal-vs-match.cr $ ./bin/code/string/equal-vs-matchString#match 15.00M ( 66.65ns) (± 8.74%) 16.0B/op 1.02× slower Regexp#=== 15.32M ( 65.27ns) (± 9.61%) 16.0B/op fastest String#=~ 14.67M ( 68.17ns) (± 8.60%) 16.0B/op 1.04× slower
gsubvs
subcode
$ crystal build --release --no-debug -o bin/code/string/gsub-vs-sub code/string/gsub-vs-sub.cr $ ./bin/code/string/gsub-vs-subString#sub 3.67M (272.77ns) (± 5.43%) 1.22kB/op fastest String#gsub 1.37M (728.87ns) (± 4.13%) 1.22kB/op 2.67× slower
includesvs
to_s.includescode
$ crystal build --release --no-debug -o bin/code/string/includes-vs-to_s.includes code/string/includes-vs-to_s.includes.cr $ ./bin/code/string/includes-vs-to_s.includesString#includes? 368.22M ( 2.72ns) (± 8.30%) 0.0B/op 1.02× slower Nil#to_s#includes? 376.21M ( 2.66ns) (± 6.76%) 0.0B/op fastest
nilvs
to_s.emptycode
$ crystal build --release --no-debug -o bin/code/string/nil-vs-to_s.empty code/string/nil-vs-to_s.empty.cr $ ./bin/code/string/nil-vs-to_s.emptyString#nil? 468.25M ( 2.14ns) (±14.49%) 0.0B/op fastest
Nil#to_s#empty? 450.24M ( 2.22ns) (±14.74%) 0.0B/op 1.04× slower
subvs
chompcode
$ crystal build --release --no-debug -o bin/code/string/sub-vs-chomp code/string/sub-vs-chomp.cr $ ./bin/code/string/sub-vs-chompString#chomp"string" 43.85M ( 22.81ns) (±12.35%) 32.0B/op fastest String#sub/regexp/ 3.57M (280.13ns) (± 5.92%) 176B/op 12.28× slower