Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

💨 Writing Fast Ruby 😍 -- Collect Common Ruby idioms.

NotificationsYou must be signed in to change notification settings

fastruby/fast-ruby

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

InErik Michaels-Ober's great talk, 'Writing Fast Ruby':Video @ Baruco 2014,Slide, he presented us with many idioms that lead to faster running Ruby code. He inspired me to document these to let more people know. I try to link to real commits so people can see that this can really have benefits in the real world.This does not mean you can always blindly replace one with another. It depends on the context (e.g.gsub versustr). Friendly reminder: Use with caution!

Each idiom has a corresponding code example that resides incode.

All results listed in README.md are running with Ruby 2.2.0p0 on OS X 10.10.1. Machine information: MacBook Pro (Retina, 15-inch, Mid 2014), 2.5 GHz Intel Core i7, 16 GB 1600 MHz DDR3. Your results may vary, but you get the idea. : )

You can checkoutthe GitHub Actions build for these benchmark results ran against different Ruby implementations.

Let's write faster code, together! <3

Analyze your code

Checkout thefasterer project - it's a static analysis that checks speed idioms written in this repo.

Measurement Tool

Usebenchmark-ips (2.0+).

Template

require"benchmark/ips"deffastenddefslowendBenchmark.ipsdo |x|x.report("fast code description"){fast}x.report("slow code description"){slow}x.compare!end

Idioms

Index

General

attr_accessor vsgetter and settercode

https://www.omniref.com/ruby/2.2.0/files/method.h?#annotation=4081781&line=47

$ ruby -v code/general/attr-accessor-vs-getter-and-setter.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------   getter_and_setter    61.240k i/100ms       attr_accessor    66.535k i/100ms-------------------------------------------------   getter_and_setter      1.660M (± 9.7%) i/s -      8.267M       attr_accessor      1.865M (± 9.2%) i/s -      9.248MComparison:       attr_accessor:  1865408.4 i/s   getter_and_setter:  1660021.9 i/s - 1.12x slower
begin...rescue vsrespond_to? for Control Flowcode
$ ruby -v code/general/begin-rescue-vs-respond-to.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------      begin...rescue    29.452k i/100ms         respond_to?   106.528k i/100ms-------------------------------------------------      begin...rescue    371.591k (± 5.4%) i/s -      1.855M         respond_to?      3.277M (± 7.5%) i/s -     16.299MComparison:         respond_to?:  3276972.3 i/s      begin...rescue:   371591.0 i/s - 8.82x slower
define_method vsmodule_eval for Defining Methodscode
$ ruby -v code/general/define_method-vs-module-eval.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------module_eval with string 125.000  i/100ms       define_method    138.000  i/100ms-------------------------------------------------module_eval with string   1.130k (±20.3%) i/s -      5.500k       define_method      1.346k (±25.9%) i/s -      6.348kComparison:       define_method:        1345.6 i/smodule_eval with string:     1129.7 i/s - 1.19x slower
String#constantize vs a comparison for inflectioncode

ActiveSupport'sString#constantize "resolves the constant reference expression in its receiver".

Read the rationale here

ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-darwin20]Calculating -------------------------------------using an if statement                          8.124M (± 1.8%) i/s -     41.357M in   5.092437s  String#constantize      2.462M (± 2.4%) i/s -     12.315M in   5.004089sComparison:using an if statement:  8123851.3 i/s  String#constantize:  2462371.2 i/s - 3.30x  (± 0.00) slower
raise vsE2MM#Raise for raising (and defining) exceptionscode

Ruby'sException2MessageMapper module allows one to define and raise exceptions with predefined messages.

$ ruby -v code/general/raise-vs-e2mmap.rbruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]Calculating -------------------------------------Ruby exception: E2MM#Raise                         2.865k i/100msRuby exception: Kernel#raise                        42.215k i/100ms-------------------------------------------------Ruby exception: E2MM#Raise                         27.270k (± 8.8%) i/s -    137.520kRuby exception: Kernel#raise                        617.446k (± 7.9%) i/s -      3.082MComparison:Ruby exception: Kernel#raise:   617446.2 i/sRuby exception: E2MM#Raise:    27269.8 i/s - 22.64x slowerCalculating -------------------------------------Custom exception: E2MM#Raise                         2.807k i/100msCustom exception: Kernel#raise                        45.313k i/100ms-------------------------------------------------Custom exception: E2MM#Raise                         29.005k (± 7.2%) i/s -    145.964kCustom exception: Kernel#raise                        589.149k (± 7.8%) i/s -      2.945MComparison:Custom exception: Kernel#raise:   589148.7 i/sCustom exception: E2MM#Raise:    29004.8 i/s - 20.31x slower
loop vswhile truecode
$ ruby -v code/general/loop-vs-while-true.rbruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]Calculating -------------------------------------          While Loop     1.000  i/100ms         Kernel loop     1.000  i/100ms-------------------------------------------------          While Loop      0.536  (± 0.0%) i/s -      3.000  in   5.593042s         Kernel loop      0.223  (± 0.0%) i/s -      2.000  in   8.982355sComparison:          While Loop:        0.5 i/s         Kernel loop:        0.2 i/s - 2.41x slower
ancestors.include? vs<=code
$ ruby -vW0 code/general/inheritance-check.rbruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]Warming up --------------------------------------  less than or equal    66.992k i/100ms  ancestors.include?    16.943k i/100msCalculating -------------------------------------  less than or equal      1.250M (± 6.4%) i/s -      6.230M in   5.006896s  ancestors.include?    192.603k (± 4.8%) i/s -    965.751k in   5.025917sComparison:  less than or equal:  1249606.0 i/s  ancestors.include?:   192602.9 i/s - 6.49x  slower

Method Invocation

call vssend vsmethod_missingcode
$ ruby -v code/method/call-vs-send-vs-method_missing.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------                call   115.094k i/100ms                send   105.258k i/100ms      method_missing   100.762k i/100ms-------------------------------------------------                call      3.811M (± 5.9%) i/s -     18.991M                send      3.244M (± 7.2%) i/s -     16.210M      method_missing      2.729M (± 9.8%) i/s -     13.401MComparison:                call:  3811183.4 i/s                send:  3244239.1 i/s - 1.17x slower      method_missing:  2728893.0 i/s - 1.40x slower
Normal way to apply method vs&method(...)code
$ ruby -v code/general/block-apply-method.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------              normal    85.749k i/100ms             &method    35.529k i/100ms-------------------------------------------------              normal      1.867M (± 7.6%) i/s -      9.347M             &method    467.095k (± 6.4%) i/s -      2.345MComparison:              normal:  1866669.5 i/s             &method:   467095.4 i/s - 4.00x slower
Function with single Array argument vs splat argumentscode
$ ruby -v code/general/array-argument-vs-splat-arguments.rbruby 2.1.7p400 (2015-08-18 revision 51632) [x86_64-linux-gnu]Calculating -------------------------------------Function with single Array argument                       157.231k i/100msFunction with splat arguments                         4.983k i/100ms-------------------------------------------------Function with single Array argument                          5.581M (± 2.0%) i/s -     27.987MFunction with splat arguments                         54.428k (± 3.3%) i/s -    274.065kComparison:Function with single Array argument:  5580972.6 i/sFunction with splat arguments:    54427.7 i/s - 102.54x slower
Hash vs OpenStruct on access assuming you already have a Hash or an OpenStructcode
$ ruby -v code/general/hash-vs-openstruct-on-access.rbruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]Calculating -------------------------------------                Hash   128.344k i/100ms          OpenStruct   110.723k i/100ms-------------------------------------------------                Hash      5.279M (± 7.0%) i/s -     26.311M          OpenStruct      3.048M (± 7.0%) i/s -     15.169MComparison:                Hash:  5278844.0 i/s          OpenStruct:  3048139.8 i/s - 1.73x slower
Hash vs OpenStruct (creation)code
$ ruby -v code/general/hash-vs-openstruct.rbruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]Calculating -------------------------------------                Hash    75.510k i/100ms          OpenStruct     9.126k i/100ms-------------------------------------------------                Hash      1.604M (±11.0%) i/s -      7.929M          OpenStruct     96.855k (± 9.9%) i/s -    483.678kComparison:                Hash:  1604259.1 i/s          OpenStruct:    96855.3 i/s - 16.56x slower
Kernel#format vs Float#round().to_scode
$ ruby -v code/general/format-vs-round-and-to-s.rbruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]Warming up --------------------------------------         Float#round   106.645k i/100ms       Kernel#format    84.304k i/100ms            String#%    78.635k i/100msCalculating -------------------------------------         Float#round      1.570M (± 3.2%) i/s - 7.892M in   5.030672s       Kernel#format      1.144M (± 3.0%) i/s - 5.733M in   5.015621s            String#%      1.047M (± 4.2%) i/s - 5.269M in   5.042970sComparison:         Float#round:  1570411.4 i/s       Kernel#format:  1144036.6 i/s - 1.37x  slower            String#%:  1046689.1 i/s - 1.50x  slower

Array

Array#bsearch vsArray#findcode

WARNING:bsearch ONLY works onsorted array. More details please see#29.

$ ruby -v code/array/bsearch-vs-find.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------                find     1.000  i/100ms             bsearch    42.216k i/100ms-------------------------------------------------                find      0.184  (± 0.0%) i/s -      1.000  in   5.434758s             bsearch    577.301k (± 6.6%) i/s -      2.913MComparison:             bsearch:   577300.7 i/s                find:        0.2 i/s - 3137489.63x slower
Array#length vsArray#size vsArray#countcode

Use#length when you only want to know how many elements in the array,#count could also achieve this. However#count should be use for counting specific elements in array.Note#size is an alias of#length.

$ ruby -v code/array/length-vs-size-vs-count.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------        Array#length   172.998k i/100ms          Array#size   168.130k i/100ms         Array#count   164.911k i/100ms-------------------------------------------------        Array#length     11.394M (± 6.1%) i/s -     56.743M          Array#size     11.303M (± 6.5%) i/s -     56.324M         Array#count      9.195M (± 8.6%) i/s -     45.680MComparison:        Array#length: 11394036.7 i/s          Array#size: 11302701.1 i/s - 1.01x slower         Array#count:  9194976.2 i/s - 1.24x slower
Array#shuffle.first vsArray#samplecode

Array#shuffle allocates an extra array.
Array#sample indexes into the array without allocating an extra array.
This is the reason why Array#sample exists.
—— @sferikrails/rails#17245

$ ruby -v code/array/shuffle-first-vs-sample.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating ------------------------------------- Array#shuffle.first    25.406k i/100ms        Array#sample   125.101k i/100ms------------------------------------------------- Array#shuffle.first    304.341k (± 4.3%) i/s -      1.524M        Array#sample      5.727M (± 8.6%) i/s -     28.523MComparison:        Array#sample:  5727032.0 i/s Array#shuffle.first:   304341.1 i/s - 18.82x slower
Array#[](0) vsArray#firstcode
$ ruby -v code/array/array-first-vs-index.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------           Array#[0]   152.751k i/100ms         Array#first   148.088k i/100ms-------------------------------------------------           Array#[0]      8.614M (± 7.0%) i/s -     42.923M         Array#first      7.465M (±10.7%) i/s -     36.874MComparison:           Array#[0]:  8613583.7 i/s         Array#first:  7464526.6 i/s - 1.15x slower
Array#[](-1) vsArray#lastcode
$ ruby -v code/array/array-last-vs-index.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------            Array#[-1]   151.940k i/100ms          Array#last   153.371k i/100ms-------------------------------------------------            Array#[-1]      8.582M (± 4.6%) i/s -     42.847M          Array#last      7.639M (± 5.7%) i/s -     38.189MComparison:            Array#[-1]:  8582074.3 i/s          Array#last:  7639254.5 i/s - 1.12x slower
Array#insert vsArray#unshiftcode
$ ruby -v code/array/insert-vs-unshift.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin10.0]Calculating -------------------------------------       Array#unshift     4.000  i/100ms        Array#insert     1.000  i/100ms-------------------------------------------------       Array#unshift     44.947  (± 6.7%) i/s -    224.000        Array#insert      0.171  (± 0.0%) i/s -      1.000  in   5.841595sComparison:       Array#unshift:       44.9 i/s        Array#insert:        0.2 i/s - 262.56x slower
Array#concat vsArray#+code

Array#+ returns a new array built by concatenating the two arrays together toproduce a third array.Array#concat appends the elements of the other array to self.This means that the + operator will create a new array each time it is called(which is expensive), while concat only appends the new element.

$ ruby -v code/array/array-concat-vs-+.rbruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]Warming up --------------------------------------        Array#concat    23.000  i/100ms             Array#+     1.000  i/100msCalculating -------------------------------------        Array#concat    217.669  (±15.2%) i/s -      1.058k in   5.016952s             Array#+      1.475  (± 0.0%) i/s -      8.000  in   5.467642sComparison:        Array#concat:      217.7 i/s             Array#+:        1.5 i/s - 147.54x  slower
Array#new vsFixnum#times + mapcode

Typical slowdown is 40-60% depending on the size of the array. See the correspondingpull request for performance characteristics.

ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]Calculating -------------------------------------           Array#new    63.875k i/100ms  Fixnum#times + map    48.010k i/100ms-------------------------------------------------           Array#new      1.070M (± 2.2%) i/s -      5.365M  Fixnum#times + map    678.097k (± 2.7%) i/s -      3.409MComparison:           Array#new:  1069837.0 i/s  Fixnum#times + map:   678097.4 i/s - 1.58x slower
Array#sort.reverse vsArray#sort_by + blockcode
$ ruby -v code/array/sort-reverse-vs-sort_by.rbruby 2.5.2p104 (2018-10-18 revision 65133) [x86_64-darwin13]Warming up --------------------------------------Array#sort.reverse                        16.231k i/100msArray#sort_by &:-@                         5.406k i/100msCalculating -------------------------------------Array#sort.reverse                        149.492k (±11.0%) i/s -    746.626k in   5.070375sArray#sort_by &:-@                         51.981k (± 8.8%) i/s -    259.488k in   5.041625sComparison:Array#sort.reverse:   149492.2 i/sArray#sort_by &:-@:    51980.6 i/s - 2.88x  (± 0.00) slower

Enumerable

Enumerable#each + push vsEnumerable#mapcode
$ ruby -v code/enumerable/each-push-vs-map.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------   Array#each + push     9.025k i/100ms           Array#map    13.947k i/100ms-------------------------------------------------   Array#each + push     99.634k (± 3.2%) i/s -    505.400k           Array#map    158.091k (± 4.2%) i/s -    794.979kComparison:           Array#map:   158090.9 i/s   Array#each + push:    99634.2 i/s - 1.59x slower
Enumerable#each vsfor loopcode
$ ruby -v code/enumerable/each-vs-for-loop.rbruby 2.2.0preview1 (2014-09-17 trunk 47616) [x86_64-darwin14]Calculating -------------------------------------            For loop    17.111k i/100ms               #each    18.464k i/100ms-------------------------------------------------            For loop    198.517k (± 5.3%) i/s -    992.438k               #each    208.157k (± 5.0%) i/s -      1.052MComparison:               #each:   208157.4 i/s            For loop:   198517.3 i/s - 1.05x slower
Enumerable#each_with_index vswhile loopcode

rails/rails#12065

$ ruby -v code/enumerable/each_with_index-vs-while-loop.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------          While Loop    22.553k i/100ms     each_with_index    11.963k i/100ms-------------------------------------------------          While Loop    240.752k (± 7.1%) i/s -      1.218M     each_with_index    126.753k (± 5.9%) i/s -    634.039kComparison:          While Loop:   240752.1 i/s     each_with_index:   126753.4 i/s - 1.90x slower
Enumerable#map...Array#flatten vsEnumerable#flat_mapcode

-- @sferikrails/rails@3413b88,Replace map.flatten with flat_map,Replace map.flatten(1) with flat_map

$ ruby -v code/enumerable/map-flatten-vs-flat_map.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------Array#map.flatten(1)     3.315k i/100ms   Array#map.flatten     3.283k i/100ms      Array#flat_map     5.350k i/100ms-------------------------------------------------Array#map.flatten(1)     33.801k (± 4.3%) i/s -    169.065k   Array#map.flatten     34.530k (± 6.0%) i/s -    173.999k      Array#flat_map     55.980k (± 5.0%) i/s -    283.550kComparison:      Array#flat_map:    55979.6 i/s   Array#map.flatten:    34529.6 i/s - 1.62x slowerArray#map.flatten(1):    33800.6 i/s - 1.66x slower
Enumerable#reverse.each vsEnumerable#reverse_eachcode

Enumerable#reverse allocates an extra array.
Enumerable#reverse_each yields each value without allocating an extra array.
This is the reason whyEnumerable#reverse_each exists.
-- @sferikrails/rails#17244

$ ruby -v code/enumerable/reverse-each-vs-reverse_each.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------  Array#reverse.each    16.746k i/100ms  Array#reverse_each    18.590k i/100ms-------------------------------------------------  Array#reverse.each    190.729k (± 4.8%) i/s -    954.522k  Array#reverse_each    216.060k (± 4.3%) i/s -      1.078MComparison:  Array#reverse_each:   216060.5 i/s  Array#reverse.each:   190729.1 i/s - 1.13x slower
Enumerable#sort_by.first vsEnumerable#min_bycode

Enumerable#sort_by performs a sort of the enumerable and allocates anew array the size of the enumerable.Enumerable#min_by doesn'tperform a sort or allocate an array the size of the enumerable.Similar comparisons hold forEnumerable#sort_by.last vsEnumerable#max_by,Enumerable#sort.first vsEnumerable#min, andEnumerable#sort.last vsEnumerable#max.

$ ruby -v code/enumerable/sort_by-first-vs-min_by.rbruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]Warming up --------------------------------------   Enumerable#min_by    15.170k i/100msEnumerable#sort_by...first                        10.413k i/100msCalculating -------------------------------------   Enumerable#min_by    157.877k (± 0.9%) i/s -    804.010k in   5.093048sEnumerable#sort_by...first                        106.831k (± 1.3%) i/s -    541.476k in   5.069403sComparison:   Enumerable#min_by:   157877.0 i/sEnumerable#sort_by...first:   106831.1 i/s - 1.48x  slower
Enumerable#detect vsEnumerable#select.firstcode
$ ruby -v code/enumerable/select-first-vs-detect.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------Enumerable#select.first  8.515k i/100ms   Enumerable#detect    33.885k i/100ms-------------------------------------------------Enumerable#select.first  89.757k (± 5.0%) i/s -      1.797M   Enumerable#detect    434.304k (± 5.2%) i/s -      8.675MComparison:   Enumerable#detect:   434304.2 i/sEnumerable#select.first:    89757.4 i/s - 4.84x slower
Enumerable#select.last vsEnumerable#reverse.detectcode
$ ruby -v code/enumerable/select-last-vs-reverse-detect.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------Enumerable#reverse.detect 62.636k i/100msEnumerable#select.last    11.687k i/100ms-------------------------------------------------Enumerable#reverse.detect 1.263M (± 8.2%) i/s -      6.326MEnumerable#select.last  119.387k (± 5.7%) i/s -    596.037kComparison:Enumerable#reverse.detect:  1263100.2 i/sEnumerable#select.last:     119386.8 i/s - 10.58x slower
Enumerable#sort vsEnumerable#sort_bycode
$ ruby -v code/enumerable/sort-vs-sort_by.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------Enumerable#sort_by (Symbol#to_proc) 2.680k i/100ms  Enumerable#sort_by                2.462k i/100ms     Enumerable#sort                1.320k i/100ms-------------------------------------------------Enumerable#sort_by (Symbol#to_proc) 25.916k (± 4.4%) i/s -    131.320k  Enumerable#sort_by                24.650k (± 5.1%) i/s -    125.562k     Enumerable#sort                14.018k (± 5.6%) i/s -     69.960kComparison:Enumerable#sort_by (Symbol#to_proc):    25916.1 i/s  Enumerable#sort_by:                   24650.2 i/s - 1.05x slower     Enumerable#sort:                   14018.3 i/s - 1.85x slower
Enumerable#inject Symbol vsEnumerable#inject Proccode

Of note,to_proc for 1.8.7 is considerable slower than the block format

$ ruby -v code/enumerable/inject-symbol-vs-block.rbruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-darwin14]Warming up --------------------------------------       inject symbol     1.893k i/100ms      inject to_proc     1.583k i/100ms        inject block     1.390k i/100msCalculating -------------------------------------       inject symbol     19.001k (± 3.8%) i/s -     96.543k      inject to_proc     15.958k (± 3.5%) i/s -     80.733k        inject block     14.063k (± 3.9%) i/s -     70.890kComparison:       inject symbol:    19001.5 i/s      inject to_proc:    15958.3 i/s - 1.19x slower        inject block:    14063.1 i/s - 1.35x slower

Date

Date.iso8601 vsDate.parsecode

When expecting well-formatted data from e.g. an API,iso8601 is faster and will raise anArgumentError on malformed input.

$ ruby -v code/date/iso8601-vs-parse.rbruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]Warming up --------------------------------------        Date.iso8601    28.880k i/100ms          Date.parse    15.805k i/100msCalculating -------------------------------------        Date.iso8601    328.035k (± 4.7%) i/s -      1.646M in   5.029287s          Date.parse    175.546k (± 3.8%) i/s -    885.080k in   5.049444sComparison:        Date.iso8601:   328035.3 i/s          Date.parse:   175545.9 i/s - 1.87x  slower

Hash

Hash#[] vsHash#fetchcode

If you use Ruby 2.2,Symbol could be more performant thanString asHash keys.Read more regarding this:Symbol GC in Ruby 2.2 andUnraveling String Key Performance in Ruby 2.2.

$ ruby -v code/hash/bracket-vs-fetch.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------     Hash#[], symbol   143.850k i/100ms  Hash#fetch, symbol   137.425k i/100ms     Hash#[], string   143.083k i/100ms  Hash#fetch, string   120.417k i/100ms-------------------------------------------------     Hash#[], symbol      7.531M (± 6.6%) i/s -     37.545M  Hash#fetch, symbol      6.644M (± 8.2%) i/s -     32.982M     Hash#[], string      6.657M (± 7.7%) i/s -     33.195M  Hash#fetch, string      3.981M (± 8.7%) i/s -     19.748MComparison:     Hash#[], symbol:  7531355.8 i/s     Hash#[], string:  6656818.8 i/s - 1.13x slower  Hash#fetch, symbol:  6643665.5 i/s - 1.13x slower  Hash#fetch, string:  3981166.5 i/s - 1.89x slower
Hash#dig vsHash#[] vsHash#fetchcode

Ruby 2.3 introducedHash#dig which is a readableand performant option for retrieval from a nested hash, returningnil if an extraction step fails.See#102 (comment) for more info.

$ ruby -v code/hash/dig-vs-\[\]-vs-fetch.rbruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]Calculating -------------------------------------            Hash#dig      5.719M (± 6.1%) i/s -     28.573M in   5.013997s             Hash#[]      6.066M (± 6.9%) i/s -     30.324M in   5.025614s          Hash#[] ||      5.366M (± 6.5%) i/s -     26.933M in   5.041403s          Hash#[] &&      2.782M (± 4.8%) i/s -     13.905M in   5.010328s          Hash#fetch      4.101M (± 6.1%) i/s -     20.531M in   5.024945s Hash#fetch fallback      2.975M (± 5.5%) i/s -     14.972M in   5.048880sComparison:             Hash#[]:  6065791.0 i/s            Hash#dig:  5719290.9 i/s - same-ish: difference falls within error          Hash#[] ||:  5366226.5 i/s - same-ish: difference falls within error          Hash#fetch:  4101102.1 i/s - 1.48x slower Hash#fetch fallback:  2974906.9 i/s - 2.04x slower          Hash#[] &&:  2781646.6 i/s - 2.18x slower
Hash[] vsHash#dupcode

Source:http://tenderlovemaking.com/2015/02/11/weird-stuff-with-hashes.html

Does this mean that you should switch to Hash[]?Only if your benchmarks can prove that it’s a bottleneck.Please please please don’t change all of your code becausethis shows it’s faster. Make sure to measure your app performance first.

$ ruby -v code/hash/bracket-vs-dup.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------              Hash[]    29.403k i/100ms            Hash#dup    16.195k i/100ms-------------------------------------------------              Hash[]    343.987k (± 8.7%) i/s -      1.735M            Hash#dup    163.516k (±10.2%) i/s -    825.945kComparison:              Hash[]:   343986.5 i/s            Hash#dup:   163516.3 i/s - 2.10x slower
Hash#fetch with argument vsHash#fetch + blockcode

Note that the speedup in the block version comes from avoiding repeated
construction of the argument. If the argument is a constant, number symbol or
something of that sort the argument version is actually slightly faster
See also#39 (comment)

$ ruby -v code/hash/fetch-vs-fetch-with-block.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin13]Calculating -------------------------------------  Hash#fetch + const   129.868k i/100ms  Hash#fetch + block   125.254k i/100ms    Hash#fetch + arg   121.155k i/100ms-------------------------------------------------  Hash#fetch + const      7.031M (± 7.0%) i/s -     34.934M  Hash#fetch + block      6.815M (± 4.2%) i/s -     34.069M    Hash#fetch + arg      4.753M (± 5.6%) i/s -     23.746MComparison:  Hash#fetch + const:  7030600.4 i/s  Hash#fetch + block:  6814826.7 i/s - 1.03x slower    Hash#fetch + arg:  4752567.2 i/s - 1.48x slower
Hash#each_key instead ofHash#keys.eachcode

Hash#keys.each allocates an array of keys;
Hash#each_key iterates through the keys without allocating a new array.
This is the reason whyHash#each_key exists.
—— @sferikrails/rails#17099

$ ruby -v code/hash/keys-each-vs-each_key.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------      Hash#keys.each    56.690k i/100ms       Hash#each_key    59.658k i/100ms-------------------------------------------------      Hash#keys.each    869.262k (± 5.0%) i/s -      4.365M       Hash#each_key      1.049M (± 6.0%) i/s -      5.250MComparison:       Hash#each_key:  1049161.6 i/s      Hash#keys.each:   869262.3 i/s - 1.21x slower

Hash#key? instead ofHash#keys.include?code

Hash#keys.include? allocates an array of keys and performs an O(n) search;
Hash#key? performs an O(1) hash lookup without allocating a new array.

$ ruby -v code/hash/keys-include-vs-key.rbruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]Calculating -------------------------------------  Hash#keys.include?      8.612k (± 2.5%) i/s -     43.248k in   5.024749s           Hash#key?      6.366M (± 5.5%) i/s -     31.715M in   5.002276sComparison:           Hash#key?:  6365855.5 i/s  Hash#keys.include?:     8612.4 i/s - 739.15x  slower
Hash#value? instead ofHash#values.include?code

Hash#values.include? allocates an array of values and performs an O(n) search;
Hash#value? performs an O(n) search without allocating a new array.

$ ruby -v code/hash/values-include-vs-value.rbruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]Calculating -------------------------------------Hash#values.include?     23.187k (± 4.3%) i/s -    117.720k in   5.086976s         Hash#value?     38.395k (± 1.0%) i/s -    194.361k in   5.062696sComparison:         Hash#value?:    38395.0 i/sHash#values.include?:    23186.8 i/s - 1.66x  slower
Hash#merge! vsHash#[]=code
$ ruby -v code/hash/merge-bang-vs-\[\]=.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------         Hash#merge!     1.023k i/100ms            Hash#[]=     2.844k i/100ms-------------------------------------------------         Hash#merge!     10.653k (± 4.9%) i/s -     53.196k            Hash#[]=     28.287k (±12.4%) i/s -    142.200kComparison:            Hash#[]=:    28287.1 i/s         Hash#merge!:    10653.3 i/s - 2.66x slower
Hash#update vsHash#[]=code
$ ruby -v code/hash/update-vs-\[\]=.rbruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin18]Warming up --------------------------------------            Hash#[]=     7.453k i/100ms         Hash#update     4.311k i/100msCalculating -------------------------------------            Hash#[]=     74.764k (± 1.9%) i/s -    380.103k in   5.085962s         Hash#update     43.220k (± 0.8%) i/s -    219.861k in   5.087364sComparison:            Hash#[]=:    74764.0 i/s         Hash#update:    43220.1 i/s - 1.73x  (± 0.00) slower
Hash#merge vsHash#**othercode
$ ruby -v code/hash/merge-vs-double-splat-operator.rbruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]Warming up --------------------------------------        Hash#**other    64.624k i/100ms          Hash#merge    38.827k i/100msCalculating -------------------------------------        Hash#**other    798.397k (± 6.9%) i/s -      4.007M in   5.053516s          Hash#merge    434.171k (± 4.5%) i/s -      2.174M in   5.018927sComparison:        Hash#**other:   798396.6 i/s          Hash#merge:   434170.8 i/s - 1.84x  slower
Hash#merge vsHash#merge!code
$ ruby -v code/hash/merge-vs-merge-bang.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------          Hash#merge    39.000  i/100ms         Hash#merge!     1.008k i/100ms-------------------------------------------------          Hash#merge    409.610  (± 7.6%) i/s -      2.067k         Hash#merge!      9.830k (± 5.8%) i/s -     49.392kComparison:         Hash#merge!:     9830.3 i/s          Hash#merge:      409.6 i/s - 24.00x slower
{}#merge!(Hash) vsHash#merge({}) vsHash#dup#merge!({})code

When we don't want to modify the original hash, and we want duplicates to be created
See#42 for more details.

$ ruby -v code/hash/merge-bang-vs-merge-vs-dup-merge-bang.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]Calculating -------------------------------------{}#merge!(Hash) do end     2.006k i/100ms        Hash#merge({})   762.000  i/100ms   Hash#dup#merge!({})   736.000  i/100ms-------------------------------------------------{}#merge!(Hash) do end     20.055k (± 2.0%) i/s -    100.300k in   5.003322s        Hash#merge({})      7.676k (± 1.2%) i/s -     38.862k in   5.063382s   Hash#dup#merge!({})      7.440k (± 1.1%) i/s -     37.536k in   5.045851sComparison:{}#merge!(Hash) do end:    20054.8 i/s        Hash#merge({}):     7676.3 i/s - 2.61x slower   Hash#dup#merge!({}):     7439.9 i/s - 2.70x slower
Hash#sort_by vsHash#sortcode

To sort hash by key.

$ ruby -v code/hash/hash-key-sort_by-vs-sort.rbruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-darwin14]Calculating -------------------------------------      sort_by + to_h    11.468k i/100ms         sort + to_h     8.107k i/100ms-------------------------------------------------      sort_by + to_h    122.176k (± 6.0%) i/s -    619.272k         sort + to_h     81.973k (± 4.7%) i/s -    413.457kComparison:      sort_by + to_h:   122176.2 i/s         sort + to_h:    81972.8 i/s - 1.49x slower
NativeHash#slice vs other slice implementations before nativecode

Since ruby 2.5, Hash comes with aslice method to select hash members by keys.

$ ruby -v code/hash/slice-native-vs-before-native.rbruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]Warming up --------------------------------------Hash#native-slice      178.077k i/100msArray#each             124.311k i/100msArray#each_w/_object   110.818k i/100msHash#select-include     66.972k i/100msCalculating -------------------------------------Hash#native-slice         2.540M (± 1.5%) i/s -     12.822M in   5.049955sArray#each                1.614M (± 1.0%) i/s -      8.080M in   5.007925sArray#each_w/_object      1.353M (± 2.6%) i/s -      6.760M in   5.000441sHash#select-include     760.944k (± 0.9%) i/s -      3.817M in   5.017123sComparison:Hash#native-slice   :  2539515.5 i/sArray#each          :  1613665.5 i/s - 1.57x  slowerArray#each_w/_object:  1352851.8 i/s - 1.88x  slowerHash#select-include :   760944.2 i/s - 3.34x  slower

Proc & Block

Block vsSymbol#to_proccode

Symbol#to_proc is considerably more concise than using block syntax.
...In some cases, it reduces the number of lines of code.
—— @sferikrails/rails#16833

$ ruby -v code/proc-and-block/block-vs-to_proc.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------               Block     4.632k i/100ms      Symbol#to_proc     5.225k i/100ms-------------------------------------------------               Block     47.914k (± 6.3%) i/s -    240.864k      Symbol#to_proc     54.791k (± 4.1%) i/s -    276.925kComparison:      Symbol#to_proc:    54791.1 i/s               Block:    47914.3 i/s - 1.14x slower
Proc#call and block arguments vsyieldcode

In MRI Ruby before 2.5, block argumentsare converted to Procs, which incurs a heap allocation.

$ ruby -v code/proc-and-block/proc-call-vs-yield.rbruby 2.4.4p296 (2018-03-28 revision 63013) [x86_64-darwin18]Calculating -------------------------------------        block.call      1.967M (± 2.0%) i/s -      9.871M in   5.019328s     block + yield      2.147M (± 3.3%) i/s -     10.814M in   5.044319s      unused block      2.265M (± 1.9%) i/s -     11.333M in   5.004522s             yield     10.436M (± 1.6%) i/s -     52.260M in   5.008851sComparison:             yield: 10436414.0 i/s      unused block:  2265399.0 i/s - 4.61x  slower     block + yield:  2146619.0 i/s - 4.86x  slower        block.call:  1967300.9 i/s - 5.30x  slower

MRI Ruby 2.5 implementsLazy Proc allocation for block parameters, which speeds things up by about 3x.:

$ ruby -v code/proc-and-block/proc-call-vs-yield.rbruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin18]Calculating -------------------------------------        block.call      1.970M (± 2.3%) i/s -      9.863M in   5.009599s     block + yield      9.075M (± 2.6%) i/s -     45.510M in   5.018369s      unused block     11.176M (± 2.7%) i/s -     55.977M in   5.012741s             yield     10.588M (± 1.9%) i/s -     53.108M in   5.017755sComparison:      unused block: 11176355.0 i/s             yield: 10588342.3 i/s - 1.06x  slower     block + yield:  9075355.5 i/s - 1.23x  slower        block.call:  1969834.0 i/s - 5.67x  slower

MRI Ruby 2.6 implementsan optimization for block.call where a block parameter is passed:

$ ruby -v code/proc-and-block/proc-call-vs-yield.rbruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin18]Calculating -------------------------------------        block.call     10.587M (± 1.2%) i/s -     52.969M in   5.003808s     block + yield     12.630M (± 0.3%) i/s -     63.415M in   5.020910s      unused block     15.981M (± 0.8%) i/s -     80.255M in   5.022305s             yield     15.352M (± 3.1%) i/s -     76.816M in   5.009404sComparison:      unused block: 15980789.4 i/s             yield: 15351931.0 i/s - 1.04x  slower     block + yield: 12630378.1 i/s - 1.27x  slower        block.call: 10587315.1 i/s - 1.51x  slower

String

String#dup vsString#+code

Note thatString.new is not the same as the options compared, since it isalwaysASCII-8BIT encoded instead of the script encoding (usuallyUTF-8).

$ ruby -v code/string/dup-vs-unary-plus.rbruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]Calculating -------------------------------------           String#+@      7.697M (± 1.4%) i/s -     38.634M in   5.020313s          String#dup      3.566M (± 1.0%) i/s -     17.860M in   5.008377sComparison:           String#+@:  7697108.3 i/s          String#dup:  3566485.7 i/s - 2.16x  slower
String#casecmp vsString#casecmp? vsString#downcase + ==code

String#casecmp? is available on Ruby 2.4 or later.Note thatString#casecmp only works on characters A-Z/a-z, not all of Unicode.

$ ruby -v code/string/casecmp-vs-downcase-\=\=.rbruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]Warming up --------------------------------------     String#casecmp?   395.796k i/100msString#downcase + ==   543.958k i/100ms      String#casecmp   730.028k i/100msCalculating -------------------------------------     String#casecmp?      3.687M (±10.9%) i/s -     18.602M in   5.158065sString#downcase + ==      5.017M (±11.3%) i/s -     25.022M in   5.089175s      String#casecmp      6.948M (± 6.0%) i/s -     35.041M in   5.062714sComparison:      String#casecmp:  6948231.0 i/sString#downcase + ==:  5017089.5 i/s - 1.38x  (± 0.00) slower     String#casecmp?:  3686650.7 i/s - 1.88x  (± 0.00) slower
String Concatenationcode
$ ruby -v code/string/concatenation.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]Warming up --------------------------------------            String#+   149.298k i/100ms       String#concat   151.505k i/100ms       String#append   153.389k i/100ms         "foo" "bar"   195.552k i/100ms  "#{'foo'}#{'bar'}"   193.784k i/100msCalculating -------------------------------------            String#+      2.977M (± 1.1%) i/s -     14.930M in   5.015179s       String#concat      3.017M (± 1.3%) i/s -     15.150M in   5.023063s       String#append      3.076M (± 1.2%) i/s -     15.492M in   5.037683s         "foo" "bar"      5.370M (± 1.0%) i/s -     26.986M in   5.026271s  "#{'foo'}#{'bar'}"      5.182M (± 4.6%) i/s -     25.967M in   5.022093sComparison:         "foo" "bar":  5369594.5 i/s  "#{'foo'}#{'bar'}":  5181745.7 i/s - same-ish: difference falls within error       String#append:  3075719.2 i/s - 1.75x slower       String#concat:  3016703.5 i/s - 1.78x slower            String#+:  2977282.7 i/s - 1.80x slower
String#match vsString.match? vsString#start_with?/String#end_with?code (start)code (end)

The regular expression approaches become slower as the tested string becomeslonger. For short strings,String#match? performs similarly toString#start_with?/String#end_with?.

⚠️
Sometimes you cant replace regexp withstart_with?,
for example:"a\nb" =~ /^b/ #=> 2 but"a\nb" =~ /\Ab/ #=> nil.
⚠️

$ ruby -v code/string/start-string-checking-match-vs-start_with.rbruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]Calculating -------------------------------------           String#=~      1.088M (± 4.0%) i/s -      5.471M in   5.034404s       String#match?      5.138M (± 5.0%) i/s -     25.669M in   5.008810s  String#start_with?      6.314M (± 4.3%) i/s -     31.554M in   5.007207sComparison:  String#start_with?:  6314182.0 i/s       String#match?:  5138115.1 i/s - 1.23x  slower           String#=~:  1088461.5 i/s - 5.80x  slower
$ ruby -v code/string/end-string-checking-match-vs-end_with.rb  ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]  Calculating -------------------------------------             String#=~    918.101k (± 6.0%) i/s -      4.650M in   5.084079s         String#match?      3.009M (± 6.8%) i/s -     14.991M in   5.005691s      String#end_with?      4.548M (± 9.3%) i/s -     22.684M in   5.034115s  Comparison:      String#end_with?:  4547871.0 i/s         String#match?:  3008554.5 i/s - 1.51x  slower             String#=~:   918100.5 i/s - 4.95x  slower
String#start_with? vsString#[].==code
$ ruby -v code/string/end-string-checking-match-vs-end_with.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------  String#start_with?      2.047M (± 4.5%) i/s -     10.242M in   5.015146s    String#[0, n] ==    711.802k (± 7.3%) i/s -      3.551M in   5.019543s   String#[RANGE] ==    651.751k (± 6.2%) i/s -      3.296M in   5.078772s   String#[0...n] ==    427.207k (± 5.7%) i/s -      2.136M in   5.019245sComparison:  String#start_with?:  2046618.9 i/s    String#[0, n] ==:   711802.3 i/s - 2.88x slower   String#[RANGE] ==:   651751.2 i/s - 3.14x slower   String#[0...n] ==:   427206.8 i/s - 4.79x slower
Regexp#=== vsRegexp#match vsRegexp#match? vsString#match vsString#=~ vsString#match?code

String#match? andRegexp#match? are available on Ruby 2.4 or later.ActiveSupportprovidesa forward compatible extension ofRegexp for older Rubies without the speedimprovement.

⚠️
Sometimes you can't replacematch withmatch?,
This is only useful for cases where you are checking
for a match and not using the resultant match object.
⚠️
Regexp#=== is also faster thanString#match but you need to switch the order of arguments.

$ ruby -v code/string/===-vs-=~-vs-match.rbruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]Calculating -------------------------------------       Regexp#match?      6.994M (± 3.0%) i/s -     35.144M in   5.029647s       String#match?      6.909M (± 3.3%) i/s -     34.663M in   5.023177s           String#=~      2.784M (± 5.2%) i/s -     13.996M in   5.043168s          Regexp#===      2.702M (± 4.5%) i/s -     13.631M in   5.056215s        Regexp#match      2.607M (± 4.9%) i/s -     13.025M in   5.009071s        String#match      2.362M (± 5.7%) i/s -     11.817M in   5.020344sComparison:       Regexp#match?:  6994107.7 i/s       String#match?:  6909055.7 i/s - same-ish: difference falls within error           String#=~:  2783577.8 i/s - 2.51x  slower          Regexp#===:  2702030.0 i/s - 2.59x  slower        Regexp#match:  2607484.0 i/s - 2.68x  slower        String#match:  2362314.8 i/s - 2.96x  slower

See#59 and#62 for discussions.

String#gsub vsString#sub vsString#[]=code
$ ruby -v code/string/gsub-vs-sub.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]Warming up --------------------------------------         String#gsub    48.360k i/100ms          String#sub    45.739k i/100msString#dup["string"]=   59.896k i/100msCalculating -------------------------------------         String#gsub    647.666k (± 3.3%) i/s -      3.240M in   5.008504s          String#sub    756.665k (± 2.0%) i/s -      3.796M in   5.019235sString#dup["string"]=   917.873k (± 1.8%) i/s -      4.612M in   5.026253sComparison:String#dup["string"]=:   917873.1 i/s          String#sub:    756664.7 i/s - 1.21x slower         String#gsub:    647665.6 i/s - 1.42x slower
String#gsub vsString#trcode

rails/rails#17257

$ ruby -v code/string/gsub-vs-tr.rbruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]Calculating -------------------------------------         String#gsub    38.268k i/100ms           String#tr    83.210k i/100ms-------------------------------------------------         String#gsub    516.604k (± 4.4%) i/s -      2.602M           String#tr      1.862M (± 4.0%) i/s -      9.320MComparison:           String#tr:  1861860.4 i/s         String#gsub:   516604.2 i/s - 3.60x slower
String#gsub vsString#tr vsString#deletecode
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]Calculating -------------------------------------         String#gsub      1.342M (± 1.3%) i/s -      6.816M in   5.079675s           String#tr      2.627M (± 1.0%) i/s -     13.387M in   5.096083s       String#delete      2.924M (± 0.7%) i/s -     14.889M in   5.093070s String#delete const      3.136M (± 2.6%) i/s -     15.866M in   5.064043sComparison: String#delete const:  3135559.1 i/s       String#delete:  2923531.8 i/s - 1.07x  slower           String#tr:  2627150.5 i/s - 1.19x  slower         String#gsub:  1342013.4 i/s - 2.34x  slower
Mutable vsImmutablecode
$ ruby -v code/string/mutable_vs_immutable_strings.rbruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin14]Calculating -------------------------------------      Without Freeze      7.279M (± 6.6%) i/s -     36.451M in   5.029785s         With Freeze      9.329M (± 7.9%) i/s -     46.370M in   5.001345sComparison:         With Freeze:  9329054.3 i/s      Without Freeze:  7279203.1 i/s - 1.28x slower
String#sub! vsString#gsub! vsString#[]=code

Note thatString#[] will throw anIndexError when given string or regexp not matched.

$ ruby -v code/string/sub\!-vs-gsub\!-vs-\[\]\=.rbruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]Calculating -------------------------------------  String#['string']=    74.512k i/100ms String#sub!'string'    52.801k i/100msString#gsub!'string'    34.480k i/100ms  String#[/regexp/]=    55.325k i/100ms String#sub!/regexp/    45.770k i/100msString#gsub!/regexp/    27.665k i/100ms-------------------------------------------------  String#['string']=      1.215M (± 6.2%) i/s -      6.110M String#sub!'string'    752.731k (± 6.2%) i/s -      3.749MString#gsub!'string'    481.183k (± 4.4%) i/s -      2.414M  String#[/regexp/]=    840.615k (± 5.3%) i/s -      4.205M String#sub!/regexp/    663.075k (± 7.8%) i/s -      3.295MString#gsub!/regexp/    342.004k (± 7.5%) i/s -      1.715MComparison:  String#['string']=:  1214845.5 i/s  String#[/regexp/]=:   840615.2 i/s - 1.45x slower String#sub!'string':   752731.4 i/s - 1.61x slower String#sub!/regexp/:   663075.3 i/s - 1.83x slowerString#gsub!'string':   481183.5 i/s - 2.52x slowerString#gsub!/regexp/:   342003.8 i/s - 3.55x slower
String#sub vsString#delete_prefixcode

Ruby 2.5 introducedString#delete_prefix.Note that this can only be used for removing characters from the start of a string.

$ ruby -v code/string/sub-vs-delete_prefix.rbruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]Calculating -------------------------------------String#delete_prefix      4.112M (± 1.8%) i/s -     20.707M in   5.037928s          String#sub    814.725k (± 1.4%) i/s -      4.088M in   5.018962sComparison:String#delete_prefix:  4111531.1 i/s          String#sub:   814725.3 i/s - 5.05x  slower
String#sub vsString#chomp vsString#delete_suffixcode

Ruby 2.5 introducedString#delete_suffixas a counterpart todelete_prefix. The performance gain overchomp issmall and during some runs the difference falls within the error margin.Note that this can only be used for removing characters from the end of a string.

$ ruby -v code/string/sub-vs-chomp-vs-delete_suffix.rbruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]Calculating -------------------------------------        String#sub    838.415k (± 1.7%) i/s -      4.214M in   5.027412s      String#chomp      3.951M (± 2.1%) i/s -     19.813M in   5.017089sString#delete_suffix    4.202M (± 2.1%) i/s -     21.075M in   5.017429sComparison:String#delete_suffix:  4202201.7 i/s        String#chomp:  3950921.9 i/s - 1.06x  slower          String#sub:   838415.3 i/s - 5.01x  slower
String#unpack1 vsString#unpack[0]code

Ruby 2.4.0 introducedunpack1 to skip creating the intermediate array object.

$ ruby -v code/string/unpack1-vs-unpack\[0\].rbruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]Warming up --------------------------------------      String#unpack1   224.291k i/100ms    String#unpack[0]   201.870k i/100msCalculating -------------------------------------      String#unpack1      4.864M (± 4.2%) i/s -     24.448M in   5.035203s    String#unpack[0]      3.778M (± 4.0%) i/s -     18.976M in   5.031253sComparison:      String#unpack1:  4864467.2 i/s    String#unpack[0]:  3777815.6 i/s - 1.29x  slower
Remove extra spaces (or other contiguous characters)code

The code is tested against contiguous spaces but should work for other chars too.

$ ruby -v code/string/remove-extra-spaces-or-other-chars.rbruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]Warming up -------------------------------------- String#gsub/regex+/     1.644k i/100ms      String#squeeze    24.681k i/100msCalculating ------------------------------------- String#gsub/regex+/     14.668k (± 5.1%) i/s -     73.980k in   5.056887s      String#squeeze    372.910k (± 8.4%) i/s -      1.851M in   5.011881sComparison:      String#squeeze:   372910.3 i/s String#gsub/regex+/:    14668.1 i/s - 25.42x  slower

Time

Time.iso8601 vsTime.parsecode

When expecting well-formatted data from e.g. an API,iso8601 is faster and will raise anArgumentError on malformed input.

$ ruby -v code/time/iso8601-vs-parse.rbruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]Warming up --------------------------------------        Time.iso8601    10.234k i/100ms          Time.parse     4.228k i/100msCalculating -------------------------------------        Time.iso8601    114.485k (± 3.5%) i/s -    573.104k in   5.012008s          Time.parse     43.711k (± 4.1%) i/s -    219.856k in   5.038349sComparison:        Time.iso8601:   114485.1 i/s          Time.parse:    43710.9 i/s - 2.62x  slower

Range

cover? vsinclude?code

cover? only check if it is within the start and end,include? needs to traverse the whole range.

$ ruby -v code/range/cover-vs-include.rbruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]Calculating -------------------------------------        range#cover?    85.467k i/100ms      range#include?     7.720k i/100ms       range#member?     7.783k i/100ms       plain compare   102.189k i/100ms-------------------------------------------------        range#cover?      1.816M (± 5.6%) i/s -      9.060M      range#include?     83.344k (± 5.0%) i/s -    416.880k       range#member?     82.654k (± 5.0%) i/s -    412.499k       plain compare      2.581M (± 6.2%) i/s -     12.876MComparison:       plain compare:  2581211.8 i/s        range#cover?:  1816038.5 i/s - 1.42x slower      range#include?:    83343.9 i/s - 30.97x slower       range#member?:    82654.1 i/s - 31.23x slower

Less idiomatic but with significant performance ruby

Checkout:https://github.com/fastruby/fast-ruby/wiki/Less-idiomatic-but-with-significant-performance-difference

Submit New Entry

Please!Edit this README.md thenSubmit a Awesome Pull Request!

Something went wrong

Code example is wrong? 😢 Got better example? 😍 Excellent!

Please open an issue orOpen a Pull Request to fix it.

Thank you in advance! 😉 🍺

One more thing

Share this with your #Rubyfriends! <3

Brought to you by@JuanitoFatas

Feel free to talk with me on Twitter! <3

Also Checkout

License

CC-BY-SA

This work is licensed under aCreative Commons Attribution-ShareAlike 4.0 International License.

Code License

CC0 1.0 Universal

To the extent possible under law, @JuanitoFatas has waived all copyright and related or neighboring rights to "fast-ruby".

This work belongs to the community.

About

💨 Writing Fast Ruby 😍 -- Collect Common Ruby idioms.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp