Skip to content
  • Petrik's avatar
    9aeffae1
    Use SecureRandom.alphanumeric for SecureRandom.base36 · 9aeffae1
    Petrik authored
    Ruby 3.3 allows passing a list of characters to
    `SecureRandom.alphanumeric`. For `SecureRandom.base36` using `choose` is
    faster than the current implementation. For `SecureRandom.base58` it is
    a bit slower.
    
    I've also added a test to make sure passing nil as the length defaults
    the length to 16.
    
    _Benchmark__
    
    ```ruby
    
    require "bundler/inline"
    
    gemfile(true) do
      source "https://rubygems.org"
    
      git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
      gem "rails", github: "rails/rails", branch: "main"
      gem "benchmark-ips"
    end
    
    require "active_support"
    require "active_support/core_ext/securerandom"
    
    module SecureRandom
      def self.fast_base36(n)
        alphanumeric(n, chars: BASE36_ALPHABET)
      end
    end
    
    [10, 100, 1000, 10000].each do |length|
      puts
      puts " #{length} ".center(80, "=")
      puts
    
      Benchmark.ips do |x|
        x.report("base36")      { SecureRandom.base36(length) }
        x.report("fast_base36") { SecureRandom.fast_base36(length) }
        x.compare!
      end
    end
    ```
    
    ```
    ====================================== 10 ======================================
    
    Warming up --------------------------------------
                  base36    20.513k i/100ms
             fast_base36    24.843k i/100ms
    Calculating -------------------------------------
                  base36    200.940k (±13.8%) i/s -    984.624k in   5.060203s
             fast_base36    235.531k (± 5.7%) i/s -      1.192M in   5.080574s
    
    Comparison:
             fast_base36:   235530.9 i/s
                  base36:   200939.9 i/s - same-ish: difference falls within error
    
    ===================================== 100 ======================================
    
    Warming up --------------------------------------
                  base36     2.746k i/100ms
             fast_base36     2.995k i/100ms
    Calculating -------------------------------------
                  base36     25.559k (± 8.5%) i/s -    129.062k in   5.087961s
             fast_base36     30.265k (± 6.6%) i/s -    152.745k in   5.070263s
    
    Comparison:
             fast_base36:    30264.7 i/s
                  base36:    25558.8 i/s - 1.18x  slower
    
    ===================================== 1000 =====================================
    
    Warming up --------------------------------------
                  base36   278.000  i/100ms
             fast_base36   308.000  i/100ms
    Calculating -------------------------------------
                  base36      2.595k (±11.6%) i/s -     12.788k in   5.007921s
             fast_base36      3.133k (± 6.1%) i/s -     15.708k in   5.033310s
    
    Comparison:
             fast_base36:     3132.6 i/s
                  base36:     2594.9 i/s - 1.21x  slower
    
    ==================================== 10000 =====================================
    
    Warming up --------------------------------------
                  base36    24.000  i/100ms
             fast_base36    34.000  i/100ms
    Calculating -------------------------------------
                  base36    256.601  (± 8.6%) i/s -      1.296k in   5.089604s
             fast_base36    322.119  (± 6.5%) i/s -      1.632k in   5.089614s
    
    Comparison:
             fast_base36:      322.1 i/s
                  base36:      256.6 i/s - 1.26x  slower
    
    ```
    9aeffae1
    Use SecureRandom.alphanumeric for SecureRandom.base36
    Petrik authored
    Ruby 3.3 allows passing a list of characters to
    `SecureRandom.alphanumeric`. For `SecureRandom.base36` using `choose` is
    faster than the current implementation. For `SecureRandom.base58` it is
    a bit slower.
    
    I've also added a test to make sure passing nil as the length defaults
    the length to 16.
    
    _Benchmark__
    
    ```ruby
    
    require "bundler/inline"
    
    gemfile(true) do
      source "https://rubygems.org"
    
      git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
      gem "rails", github: "rails/rails", branch: "main"
      gem "benchmark-ips"
    end
    
    require "active_support"
    require "active_support/core_ext/securerandom"
    
    module SecureRandom
      def self.fast_base36(n)
        alphanumeric(n, chars: BASE36_ALPHABET)
      end
    end
    
    [10, 100, 1000, 10000].each do |length|
      puts
      puts " #{length} ".center(80, "=")
      puts
    
      Benchmark.ips do |x|
        x.report("base36")      { SecureRandom.base36(length) }
        x.report("fast_base36") { SecureRandom.fast_base36(length) }
        x.compare!
      end
    end
    ```
    
    ```
    ====================================== 10 ======================================
    
    Warming up --------------------------------------
                  base36    20.513k i/100ms
             fast_base36    24.843k i/100ms
    Calculating -------------------------------------
                  base36    200.940k (±13.8%) i/s -    984.624k in   5.060203s
             fast_base36    235.531k (± 5.7%) i/s -      1.192M in   5.080574s
    
    Comparison:
             fast_base36:   235530.9 i/s
                  base36:   200939.9 i/s - same-ish: difference falls within error
    
    ===================================== 100 ======================================
    
    Warming up --------------------------------------
                  base36     2.746k i/100ms
             fast_base36     2.995k i/100ms
    Calculating -------------------------------------
                  base36     25.559k (± 8.5%) i/s -    129.062k in   5.087961s
             fast_base36     30.265k (± 6.6%) i/s -    152.745k in   5.070263s
    
    Comparison:
             fast_base36:    30264.7 i/s
                  base36:    25558.8 i/s - 1.18x  slower
    
    ===================================== 1000 =====================================
    
    Warming up --------------------------------------
                  base36   278.000  i/100ms
             fast_base36   308.000  i/100ms
    Calculating -------------------------------------
                  base36      2.595k (±11.6%) i/s -     12.788k in   5.007921s
             fast_base36      3.133k (± 6.1%) i/s -     15.708k in   5.033310s
    
    Comparison:
             fast_base36:     3132.6 i/s
                  base36:     2594.9 i/s - 1.21x  slower
    
    ==================================== 10000 =====================================
    
    Warming up --------------------------------------
                  base36    24.000  i/100ms
             fast_base36    34.000  i/100ms
    Calculating -------------------------------------
                  base36    256.601  (± 8.6%) i/s -      1.296k in   5.089604s
             fast_base36    322.119  (± 6.5%) i/s -      1.632k in   5.089614s
    
    Comparison:
             fast_base36:      322.1 i/s
                  base36:      256.6 i/s - 1.26x  slower
    
    ```
Loading