neumachen
1/14/2016 - 12:41 AM

Validator Speeds

Validator Speeds

require 'poro_validator'
require 'dry-validation'
require 'active_model'
require 'benchmark'

poro_validator = Class.new do
  include PoroValidator.validator

  validates :name, presence: true
  validates :age, numeric: { minimum: 18 }
end.new

schema = Class.new(Dry::Validation::Schema) do
  key(:name, &:filled?)
  key(:age) { |v| v.int? & v.gt?(18) }
end.new

class User
  include ActiveModel::Validations

  validates :name, presence: true
  validates :age, numericality: { greater_than: 18 }

  attr_reader :name, :age

  def initialize(attrs)
    @name, @age = attrs.values_at(:name, :age)
  end
end

count = 10_000
users = count.times.map { |i| { user: "User #{i}", age: 17 } }

Benchmark.bmbm do |x|
  x.report('PV: 1 thread') do
    users.each do |user|
      poro_validator.valid?(user)
      poro_validator.errors.full_messages
    end
  end

  x.report('DV: 1 thread') do
    users.each { |user| schema.(user).messages }
  end

  x.report('AM: 1 thread') do
    users.each { |user| User.new(user).validate }
  end

  x.report('PV: 2 threads') do
    g1, g2 = users.each_slice(count/2).to_a

    t1 = Thread.new do
      g1.each do |user|
        poro_validator.valid?(user)
        poro_validator.errors.full_messages
      end
    end

    t2 = Thread.new do
      g2.each do |user|
        poro_validator.valid?(user)
        poro_validator.errors.full_messages
      end
    end

    t1.join
    t2.join
  end

  x.report('DV: 2 threads') do
    g1, g2 = users.each_slice(count/2).to_a

    t1 = Thread.new { g1.each { |user| schema.(user).messages } }
    t2 = Thread.new { g2.each { |user| schema.(user).messages } }

    t1.join
    t2.join
  end

  x.report('AM: 2 threads') do
    g1, g2 = users.each_slice(count/2).to_a

    t1 = Thread.new { g1.each { |user| User.new(user).validate } }
    t2 = Thread.new { g2.each { |user| User.new(user).validate } }

    t1.join
    t2.join
  end
end