Skip to content

Instantly share code, notes, and snippets.

@matsadler
Created June 18, 2012 16:34
Show Gist options
  • Save matsadler/2949277 to your computer and use it in GitHub Desktop.
Save matsadler/2949277 to your computer and use it in GitHub Desktop.
ActiveRecord slowdown with Threads
Create a database called `jruby_ar_concurrency_slowdown` (or edit helper.rb)
and run setup.sql
Install JRuby 1.6.7.2 and make sure it's in your path and available as `ruby`
(rbenv is what I've been using)
Run `bundle exec ruby bench.rb`, you should see the concurrent version taking
roughly 1/3 the time of the sequential versions.
Run `bundle exec ruby bug.rb`, and you'll see for some strange reason when you
explicitly require "active_record/relation" ahead of it being autoloaded the
concurrent benchmarks actually take longer.
Run `bundle exec ruby workaround.rb`, and you should see the concurrent
benchmarks are fast again, purely from forcing the autoload of
"active_record/relation" ahead of the require.
require "benchmark"
require_relative "helper"
Benchmark.bmbm do |x|
repeats = 100
concurrency = 10
# benchmarking has_many :through association
x.report("sequential") do
repeats.times do
Foo.first.bazs.all
end
end
# performing the requests concurrently should result in a speed up
x.report("concurrent") do
repeat_concurrently(repeats, concurrency) do
Foo.first.bazs.all
end
end
end
require "active_record"
require "active_record/relation"
require_relative "bench"
source :rubygems
gem "activerecord", "3.1.4"
platforms :mri do
gem "mysql2"
end
platforms :jruby do
gem "activerecord-jdbcmysql-adapter"
end
GEM
remote: http://rubygems.org/
specs:
activemodel (3.1.4)
activesupport (= 3.1.4)
builder (~> 3.0.0)
i18n (~> 0.6)
activerecord (3.1.4)
activemodel (= 3.1.4)
activesupport (= 3.1.4)
arel (~> 2.2.3)
tzinfo (~> 0.3.29)
activerecord-jdbc-adapter (1.2.2)
activerecord-jdbcmysql-adapter (1.2.2)
activerecord-jdbc-adapter (~> 1.2.2)
jdbc-mysql (~> 5.1.0)
activesupport (3.1.4)
multi_json (~> 1.0)
arel (2.2.3)
builder (3.0.0)
i18n (0.6.0)
jdbc-mysql (5.1.13)
multi_json (1.3.6)
mysql2 (0.3.10)
tzinfo (0.3.33)
PLATFORMS
java
ruby
DEPENDENCIES
activerecord (= 3.1.4)
activerecord-jdbcmysql-adapter
mysql2
require "active_record"
require "activerecord-jdbc-adapter" if RUBY_ENGINE == "jruby"
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:host => "localhost",
:username => "root",
:database => "jruby_ar_concurrency_slowdown",
:pool => 50)
class Foo < ActiveRecord::Base
has_many :bars
has_many :bazs, :through => :bars
end
class Bar < ActiveRecord::Base
belongs_to :foo
belongs_to :baz
end
class Baz < ActiveRecord::Base
has_many :bars
end
def repeat_concurrently(repeats, concurrency, &block)
unless repeats % concurrency == 0
raise "#{repeats} doesn't divide evenly between #{concurrency}"
end
indevidual_repeats = repeats / concurrency
threads = []
concurrency.times do
threads << Thread.new do
indevidual_repeats.times {block.call}
ActiveRecord::Base.clear_active_connections!
end
end
threads.map(&:join)
end
CREATE TABLE `foos` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
CREATE TABLE `bars` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`foo_id` int(11) DEFAULT NULL,
`baz_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `bazs` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
INSERT INTO `foos` (`id`) VALUES (1);
INSERT INTO `bars` (`id`, `foo_id`, `baz_id`) VALUES (2, 1, 3);
INSERT INTO `bazs` (`id`) VALUES (3);
require "active_record"
ActiveRecord::Relation
require "active_record/relation"
require_relative "bench"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment