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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance by caching regexes? #90

Closed
asterite opened this issue Nov 15, 2017 · 3 comments
Closed

Improve performance by caching regexes? #90

asterite opened this issue Nov 15, 2017 · 3 comments

Comments

@asterite
Copy link
Contributor

Hi @soveran! 馃槃

I noticed that to consume segments a regex is created each and every time the segment tries to be matched:

matchdata = env[Rack::PATH_INFO].match(/\A\/(#{pattern})(\/|\z)/)

So I made this benchmark:

require_relative "./lib/cuba"

Cuba.define do
  on "users" do
    on ":id" do |id|
      on root do
        res.write "User #{id}"
      end

      on "projects" do
        on ":project_id" do |project_id|
          res.write "User #{id}, Project #{project_id}"
        end
      end
    end
  end
end

env1 = { "PATH_INFO" => "/users/1", "SCRIPT_NAME" => "/" }
env2 = { "PATH_INFO" => "/users/1/projects/2", "SCRIPT_NAME" => "/" }

time = Time.now
30_000.times do
  Cuba.call(env1)
  Cuba.call(env2)
end
puts Time.now - time

On my machine it takes about 4 seconds to complete.

Now I cache the regexes with this diff:

diff --git a/lib/cuba.rb b/lib/cuba.rb
index b12e9f3..b4090fe 100644
--- a/lib/cuba.rb
+++ b/lib/cuba.rb
@@ -5,6 +5,7 @@ class Cuba
   EMPTY   = "".freeze
   SEGMENT = "([^\\/]+)".freeze
   DEFAULT = "text/html; charset=utf-8".freeze
+  REGEXES = Hash.new { |h, pattern| h[pattern] = /\A\/(#{pattern})(\/|\z)/ }
 
   class Response
     LOCATION = "Location".freeze
@@ -211,7 +212,7 @@ class Cuba
   private :try
 
   def consume(pattern)
-    matchdata = env[Rack::PATH_INFO].match(/\A\/(#{pattern})(\/|\z)/)
+    matchdata = env[Rack::PATH_INFO].match(REGEXES[pattern])
 
     return false unless matchdata

I run the snippet above and it now takes 2 seconds.

Twice as fast!

Do you think this is a good change? I think it's harmless: the routes of an app are fixed (not dynamic) so that REGEXES hash will reach a reasonable maximum size. Plus it can help with routes like ":id" where they might be used in several places.

What do you think?

@soveran
Copy link
Owner

soveran commented Nov 15, 2017

I kind of replied with a 馃憤 and a 鉂わ笍
I think this is perfect, let's go for it. Do you want to submit the change as a PR?

@asterite
Copy link
Contributor Author

Sure! I'll send a PR soon :-)

@asterite
Copy link
Contributor Author

Closed by #91

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

No branches or pull requests

2 participants