💎 Fast Crystal

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:

Measurement Tool

Use Crystal's built-in benchmark.

Run the Benchmarks

$ make

Template

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

Idioms

Index

Test in Crystal 0.35.1 (2020-06-19) LLVM: 10.0.0 Default target: x86_64-apple-macosx

Array

first vs 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

insert vs unshift code

$ crystal build --release --no-debug -o bin/code/array/insert-vs-unshift code/array/insert-vs-unshift.cr
$ ./bin/code/array/insert-vs-unshift

 Array#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

last vs 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

range vs times.map code

$ 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.map

Range#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

Enumerable

each push vs map code

$ 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-map

             Array#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

each vs loop code

$ crystal build --release --no-debug -o bin/code/enumerable/each-vs-loop code/enumerable/each-vs-loop.cr
$ ./bin/code/enumerable/each-vs-loop

While 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_index vs while loop code

$ 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-loop

     While 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 flatten vs flat_map code

$ 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_map

   Array#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.each vs reverse_each code

$ 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_each

Array#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

sort vs sort_by code

$ 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_by

   Enumerable#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

General

Assignment code

$ crystal build --release --no-debug -o bin/code/general/assignment code/general/assignment.cr
$ ./bin/code/general/assignment

Sequential 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

hash vs struct vs namedtuple code

$ 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-namedtuple

NamedTuple 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

loop vs while_true code

$ 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_true

 While 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_argument vs named_argument code

$ 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_argument

     Named 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

property vs getter_and_setter code

$ 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_setter

         property  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

Hash

[]? 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

bracket vs fetch code

$ crystal build --release --no-debug -o bin/code/hash/bracket-vs-fetch code/hash/bracket-vs-fetch.cr
$ ./bin/code/hash/bracket-vs-fetch

   Hash#[]  95.60M ( 10.46ns) (± 6.16%)  0.0B/op   1.02× slower
Hash#fetch  97.08M ( 10.30ns) (± 9.36%)  0.0B/op        fastest

clone vs dup code

$ crystal build --release --no-debug -o bin/code/hash/clone-vs-dup code/hash/clone-vs-dup.cr
$ ./bin/code/hash/clone-vs-dup

  Hash#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 each vs each_key code

$ 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_key

Hash#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 bang vs []= 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

Namedtuple

bracket vs fetch code

$ crystal build --release --no-debug -o bin/code/namedtuple/bracket-vs-fetch code/namedtuple/bracket-vs-fetch.cr
$ ./bin/code/namedtuple/bracket-vs-fetch

   NamedTuple#[] 294.37M (  3.40ns) (±19.52%)  0.0B/op   1.00× slower
NamedTuple#fetch 295.49M (  3.38ns) (±19.80%)  0.0B/op        fastest

fetch vs fetch_with_block code

$ 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_block

NamedTuple#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

Proc & Block

block vs to_proc code

$ 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_proc

         Block 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 call vs yield code

$ 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-yield

    block.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

String

Concatenation code

$ crystal build --release --no-debug -o bin/code/string/concatenation code/string/concatenation.cr
$ ./bin/code/string/concatenation

 String#+  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-match vs end_with code

$ 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_with

String#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

Equal-substring-of-char code

$ 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

equal vs match code

$ crystal build --release --no-debug -o bin/code/string/equal-vs-match code/string/equal-vs-match.cr
$ ./bin/code/string/equal-vs-match

String#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

gsub vs sub code

$ crystal build --release --no-debug -o bin/code/string/gsub-vs-sub code/string/gsub-vs-sub.cr
$ ./bin/code/string/gsub-vs-sub

 String#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

includes vs to_s.includes code

$ 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.includes

  String#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

nil vs to_s.empty code

$ 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.empty

    String#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

sub vs chomp code

$ crystal build --release --no-debug -o bin/code/string/sub-vs-chomp code/string/sub-vs-chomp.cr
$ ./bin/code/string/sub-vs-chomp

String#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

You may also like