Attributes Unwrapped: Lessons under the surface of active record

1,258 views

Published on

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

Published in: Technology, Business
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,258
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
15
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

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 ♥)

×