Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String#=~ faster than String#match #59

Merged

Conversation

@schneems
Copy link
Contributor

@schneems schneems commented Aug 6, 2015

If you're only looking for presence of a match and don't need the matchdata, use String#=~

schneems/rails@1bf50ba#commitcomment-12572839

If you're only looking for presence of a match and don't need the matchdata, use String#=~ 

schneems/rails@1bf50ba#commitcomment-12572839
schneems referenced this issue in schneems/rails Aug 6, 2015
In `apply_inflections` a string is down cased and some whitespace stripped in the front (which allocate strings). This would normally be fine, however `uncountables` is a fairly small array (10 elements out of the box) and this method gets called a TON. Instead we can keep an array of valid regexes for each uncountable so we don't have to allocate new strings.

This change buys us 325,106 bytes of memory and 3,251 fewer objects per request.
@Arcovion
Copy link
Collaborator

@Arcovion Arcovion commented Aug 6, 2015

Regexp#=== is a tiny bit faster on my machine, worth including:

require 'benchmark/ips'

def fastest
  /boo/ === 'foo'.freeze
end

def fast
  'foo'.freeze =~ /boo/
end

def slow
  'foo'.freeze.match(/boo/)
end

Benchmark.ips do |bm|
  bm.report("Regexp#===") { fastest }
  bm.report("String#=~") { fast }
  bm.report("String#match") { slow }
  bm.compare!
end
Calculating -------------------------------------
          Regexp#===   116.319k i/100ms
           String#=~   119.576k i/100ms
        String#match   102.506k i/100ms
-------------------------------------------------
          Regexp#===      3.048M (± 1.5%) i/s -     15.238M
           String#=~      2.988M (± 1.4%) i/s -     14.947M
        String#match      2.482M (± 1.2%) i/s -     12.506M

Comparison:
          Regexp#===:  3047884.6 i/s
           String#=~:  2988148.2 i/s - 1.02x slower
        String#match:  2481615.6 i/s - 1.23x slower

Loading

@schneems
Copy link
Contributor Author

@schneems schneems commented Aug 6, 2015

Yep

Calculating -------------------------------------
           String#=~    66.023k i/100ms
        String#match    60.124k i/100ms
          String#===    70.747k i/100ms
-------------------------------------------------
           String#=~      1.798M (±10.3%) i/s -      8.913M
        String#match      1.374M (± 9.7%) i/s -      6.854M
          String#===      1.847M (± 9.8%) i/s -      9.197M

Seems good. How should I report this? I would like to have all 3 examples in the code and reported.

Loading

@Arcovion
Copy link
Collaborator

@Arcovion Arcovion commented Aug 6, 2015

Edited my comment as String#=== was wrong, I meant Regexp#===
Added example of how it might look...

Loading

@JuanitoFatas
Copy link
Owner

@JuanitoFatas JuanitoFatas commented Aug 7, 2015

How about list all possibilities (code/string/===-vs-=~-vs-match.rb)?

require "benchmark/ips"

def fastest
  "foo".freeze === /boo/
end

def faster
  "foo".freeze =~ /boo/
end

def fast
  /boo/ === "foo".freeze
end

def slow
  "foo".freeze.match(/boo/)
end

Benchmark.ips do |x|
  x.report("String#===") { fastest }
  x.report("Regexp#===") { faster }
  x.report("String#=~") { fast }
  x.report("String#match") { slow }
  x.compare!
end
ruby -v code/string/match-vs-=\~.rb
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
Calculating -------------------------------------
          String#===   143.440k i/100ms
          Regexp#===    94.853k i/100ms
           String#=~    91.999k i/100ms
        String#match    88.397k i/100ms
-------------------------------------------------
          String#===      5.637M (± 7.4%) i/s -     28.114M
          Regexp#===      2.599M (± 5.4%) i/s -     12.995M
           String#=~      2.318M (± 7.7%) i/s -     11.592M
        String#match      1.905M (± 8.4%) i/s -      9.458M

Comparison:
          String#===:  5637360.8 i/s
          Regexp#===:  2599326.4 i/s - 2.17x slower
           String#=~:  2318149.8 i/s - 2.43x slower
        String#match:  1905484.8 i/s - 2.96x slower

Loading

@Arcovion
Copy link
Collaborator

@Arcovion Arcovion commented Aug 7, 2015

String#=== doesn't work, it's not the correct result.

Loading

@JuanitoFatas
Copy link
Owner

@JuanitoFatas JuanitoFatas commented Aug 7, 2015

String#=== doesn't work, it's not the correct result.

Yup. The #59 (comment) is wrong.

Let's keep this simple since the regexp need to flip the string to be compared to the end. Which is counterintuitive

Loading

JuanitoFatas added a commit that referenced this issue Aug 7, 2015
@JuanitoFatas JuanitoFatas merged commit df633ee into JuanitoFatas:master Aug 7, 2015
1 check passed
Loading
schneems added a commit to schneems/rails that referenced this issue Aug 7, 2015
@schneems
Copy link
Contributor Author

@schneems schneems commented Aug 7, 2015

It's a pretty big speed boost, we would have to rename it to Regexp#=== and we could put a warning in about not switching the arguments cause you'll get the wrong results

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

3 participants