Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Attributes Unwrapped: Lessons under the surface of active record

1,291 views

Published on

Ведущий разработчик Ruby on Rails (Rails Core member) Джон Лейтон не так давно работал над совершенствованием реализации работы с атрибутами в Active Record. Он расскажет о своем опыте работы над важной для производительности областью Rails, даст советы и расскажет о техниках, которые могут быть применены к собственным приложениям слушателей.
Говоря о будущем, Джон также расскажет о своих идеях по изменению API работы с атрибутами в лучшую сторону; эти изменения могут появиться в Rails 4.0.

Published in: Technology, Business
  • Be the first to comment

Attributes Unwrapped: Lessons under the surface of active record

  1. 1. Attributes Unwrapped
  2. 2. @jonleighton
  3. 3. I lied to you
  4. 4. Measure
  5. 5. MeasureRefactor
  6. 6. MeasureRefactorOptimise
  7. 7. LET’S DO SCIENCE
  8. 8. gem rails, 3.2.0require active_recordActiveRecord::Base .establish_connection( :adapter => sqlite3, :database => :memory:)
  9. 9. ActiveRecord::Schema.define do create_table :posts do |t| t.string :title endendclass Post < ActiveRecord::Baseendp = Post.create(:title => "lol")
  10. 10. require benchmarkn = 1_000_000Benchmark.report(20) do |r| r.report(attribute) do n.times { p.title } end r.report(read_attribute) do n.times { p[:title] } endend
  11. 11. attribute 1.09 sread_attribute 2.87 s
  12. 12. gem installbenchmark_suite
  13. 13. require benchmark/ipsBenchmark.ips do |r| r.report(attribute) do p.title end r.report(read_attribute) do p[:title] endend
  14. 14. attribute 828,648read_attribute 299,856
  15. 15. Ruby 1.9
  16. 16. Ruby 1.8
  17. 17. Ruby 1.8 oops!
  18. 18. define_method
  19. 19. method compilation
  20. 20. create_table :roflcopters do |t| t.string " ROFL:ROFL:ROFL:ROFL" t.string " _^____ " t.string " L __/ [] " t.string "LOL===_ " t.string " L _________] " t.string " I I " t.string " --------/ "end
  21. 21. if compilable? class_eval <<-STR def #{attr_name} ... end STRelse define_method attr_name do ... endend
  22. 22. attr_name =~/A[a-zA-Z_]w*[!?=]?z/
  23. 23. :title =~/A[a-zA-Z_]w*[!?=]?z/
  24. 24. Ruby 1.9:title =~ /.../# => true
  25. 25. Ruby 1.8:title =~ /.../# => false
  26. 26. def __temp__ ...endalias "@#>" :__temp__undef_method :__temp__
  27. 27. DOdef __temp__ NT ... USend E THalias "@#>" :__temp__ ISundef_method :__temp__
  28. 28. API Changes
  29. 29. def title self[:title].upcaseend
  30. 30. def title super.upcaseend
  31. 31. module A def foo "bar" endend
  32. 32. class B include A def foo super.upcase endend
  33. 33. Don’t fight Ruby <3 <3 <3
  34. 34. #read_attribute#[]
  35. 35. def read_attribute(name) name = "_#{name}" if respond_to?(name) send(name) else # other stuff endend
  36. 36. Module.new
  37. 37. def read_attribute(name) mod = self.class.methods_module if mod.respond_to?(name) mod.send(name, @attributes) else # other stuff endend
  38. 38. Module.new.respond_to?(:name)# => true
  39. 39. Module.new { extend self }
  40. 40. Module.new { extend self }mod.method_defined?(:name)
  41. 41. IN SAModule.new { extend self } NE HA CKmod.method_defined?(:name)
  42. 42. Still too slow ☹
  43. 43. gem installperftools.rb
  44. 44. if attr_name == id attr_name = self.class.primary_keyend
  45. 45. No code is faster than no code
  46. 46. def title cast @attributes[title]end
  47. 47. def title cast @attributes[:title]end
  48. 48. class A def initialize @attributes = { :foo => 1 } end def foo @attributes[:foo] endend
  49. 49. class B def initialize @attributes = { foo => 1 } end def foo @attributes[foo] endend
  50. 50. Benchmark.ips do |r| r.report(symbol) { a.foo } r.report(string) { b.foo }end
  51. 51. code = "@attributes[foo]"iseq = RubyVM::InstructionSequence .compile(code)puts iseq.disassemble
  52. 52. trace 1getinstancevariable :@attributesputstring "foo"opt_aref <ic:2>leave
  53. 53. trace 1getinstancevariable :@attributesputobject :fooopt_aref <ic:2>leave
  54. 54. DEFINE_INSNputstring(VALUE str)()(VALUE val){ val = rb_str_resurrect(str);}
  55. 55. DEFINE_INSNputobject(VALUE val)()(VALUE val){ /* */}
  56. 56. code = "@attributes[foo]"compiled = Rubinius::Compiler .compile_string(code)puts compiled.decode
  57. 57. push_ivar 0push_literal "foo"string_dupsend_stack :[], 1poppush_trueret
  58. 58. push_ivar 0push_literal :foosend_stack :[], 1poppush_trueret
  59. 59. jruby --bytecode -e "@attributes[foo]"
  60. 60. RubyString
  61. 61. RubyStringRubySymbol
  62. 62. Performance problems are a code smell
  63. 63. Be a scientist
  64. 64. But...
  65. 65. Avoid roflscaling!
  66. 66. ER! OV S ITThanks!
  67. 67. Thanks! IT S OV E R!(♥ @tenderlove ♥)

×