Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> Ruby

बेंचमार्किंग रूबी परिशोधन

यदि आप किसी भी पिछली कहानी को जाने बिना रूबी शोधन के लिए Google पर खोज करते हैं, तो आपको यह विचार आ सकता है कि शोधन धीमा है।

जैसा कि वे मूल रूप से प्रस्तावित थे, शोधन धीमा होता। वे दुभाषिए के लिए मेथड लुकअप जैसी चीजों को ऑप्टिमाइज़ करना असंभव बना देते।

लेकिन शोधन का वास्तविक कार्यान्वयन मूल प्रस्ताव की तुलना में थोड़ा अधिक सीमित है। इसलिए मैंने सोचा कि शोधन पर बेंचमार्क की एक श्रृंखला चलाना दिलचस्प होगा जैसा कि आज रूबी में मौजूद है।

TL;DR

शोधन धीमा नहीं है। या कम से कम वे "सामान्य" तरीकों से धीमे नहीं लगते।

डमी लोड

हम बेंचमार्किंग मेथड कॉल्स करने जा रहे हैं। तो हमें कुछ तरीकों की आवश्यकता होगी।

यहाँ, मैं एक मूर्खतापूर्ण छोटी विधि के दो संस्करण बना रहा हूँ। एक "सामान्य" है और दूसरा परिशोधन के अंदर है:

# As our "dummy load" we're going to create shrugs. 
# 1 shrug == "¯\_(ツ)_/¯"
# 2 shrugs == "¯\_(ツ)_/¯¯\_(ツ)_/¯"
# ...etc.

SHRUG = "¯\_(ツ)_/¯"

# We'll make a refinement that generates shrugs
module Shruggable
  refine Fixnum do
    def shrugs
      SHRUG * self
    end
  end
end

# ...and we'll make a normal method that also generates shrugs
def integer_to_shrugs(n)
  SHRUG * n
end

हम सीधे शोधन का उपयोग नहीं कर सकते। इसे using . के माध्यम से सक्रिय किया जाना है बयान। तो मैं दो वर्ग बनाउंगा जो समान व्यवहार करते हैं। एक शोधन का उपयोग करता है, और दूसरा नहीं करता है।

class TestUsing
  using Shruggable
  def noop
  end

  def shrug
    10.shrugs
  end
end

class TestWithoutUsing
  def noop
  end

  def shrug
    integer_to_shrugs(10)
  end
end

बेंचमार्क

मैं जानना चाहता था कि क्या शोधन का उपयोग करके वस्तुओं को त्वरित करना, या परिशोधन के माध्यम से जोड़े गए तरीकों को कॉल करना धीमा था।

सभी बेंचमार्क OSX El Capitan पर MRI 2.2.2 के साथ चलाए गए।

ऑब्जेक्ट क्रिएशन

क्या "उपयोग" कीवर्ड प्रारंभ करने के लिए कक्षा को धीमा कर देता है? नहीं।

Benchmark.ips do |bm|
  bm.report("class initialization") { TestUsing.new }
  bm.report("class initialization WITH using") { TestWithoutUsing.new }
  bm.compare!
end

# Calculating -------------------------------------
# class initialization   142.929k i/100ms
# class initialization WITH using
#                        145.323k i/100ms
# -------------------------------------------------
# class initialization      5.564M (± 8.3%) i/s -     27.728M
# class initialization WITH using
#                           5.619M (± 7.4%) i/s -     28.047M
# Comparison:
# class initialization WITH using:  5618601.3 i/s
# class initialization:  5564116.5 i/s - 1.01x slower

विधि कॉल

क्या परिशोधन "सामान्य" विधि लुकअप गति को प्रभावित करते हैं? नहीं।

Benchmark.ips do |bm|
  bm.report("run method") { TestUsing.new.noop }
  bm.report("run method in class WITH using") { TestWithoutUsing.new.noop }
  bm.compare!
end

# Calculating -------------------------------------
#           run method   141.905k i/100ms
# run method in class WITH using
#                        144.435k i/100ms
# -------------------------------------------------
#           run method      5.010M (± 6.4%) i/s -     24.975M
# run method in class WITH using
#                           5.086M (± 5.3%) i/s -     25.421M
# Comparison:
# run method in class WITH using:  5086262.3 i/s
#           run method:  5010273.6 i/s - 1.02x slower

एक समान "सामान्य" विधि का उपयोग करने की तुलना में एक शोधन धीमी से एक विधि का उपयोग कर रहा है? नहीं।

Benchmark.ips do |bm|
  bm.report("shrug") { TestUsing.new.shrug }
  bm.report("shrug via refinement") { TestWithoutUsing.new.shrug }
  bm.compare!
end

# Calculating -------------------------------------
#                shrug    96.089k i/100ms
# shrug via refinement    95.559k i/100ms
# -------------------------------------------------
#                shrug      1.825M (± 9.3%) i/s -      9.128M
# shrug via refinement      1.929M (± 6.2%) i/s -      9.651M

# Comparison:
# shrug via refinement:  1928841.5 i/s
#                shrug:  1825069.4 i/s - 1.06x slower

डेक को स्टैक करना

क्या मैं एक शोधन बेंचमार्क को अपने नियंत्रण से धीमा बनाने के लिए कुछ कर सकता हूँ? ¯\_(ツ)_/¯


# Does repeated evaluation of the `using` keyword affect performance. Only slightly. 
# This is an unfair test, but I really wanted to force refinements to be slower
# in SOME use case :)
Benchmark.ips do |bm|
  bm.report("inline shrug") { integer_to_shrugs(10) }
  bm.report("inline shrug via refinement") do
    using Shruggable
    10.shrugs
  end
  bm.compare!
end

# Calculating -------------------------------------
#         inline shrug   100.460k i/100ms
# inline shrug via refinement
#                         72.131k i/100ms
# -------------------------------------------------
#         inline shrug      2.507M (± 5.2%) i/s -     12.557M
# inline shrug via refinement
#                           1.498M (± 4.3%) i/s -      7.502M

# Comparison:
#         inline shrug:  2506663.9 i/s
# inline shrug via refinement:  1497747.6 i/s - 1.67x slower

पूर्ण कोड

यदि आप स्वयं बेंचमार्क चलाना चाहते हैं, तो यह कोड है।

require 'benchmark/ips'


# As our "dummy load" we're going to create shrugs. 
# 1 shrug == "¯\_(ツ)_/¯"
# 2 shrugs == "¯\_(ツ)_/¯¯\_(ツ)_/¯"
# ...etc.

SHRUG = "¯\_(ツ)_/¯"

# We'll make a refinement that generates shrugs
module Shruggable
  refine Fixnum do
    def shrugs
      SHRUG * self
    end
  end
end

# ...and we'll make a normal method that also generates shrugs
def integer_to_shrugs(n)
  SHRUG * n
end

# Now we'll define two classes. The first uses refinments. The second doesn't. 
class TestUsing
  using Shruggable
  def noop
  end

  def shrug
    10.shrugs
  end
end

class TestWithoutUsing
  def noop
  end

  def shrug
    integer_to_shrugs(10)
  end
end

# Does the "using" keyword make a class slower to initialize? Nope. 
Benchmark.ips do |bm|
  bm.report("class initialization") { TestUsing.new }
  bm.report("class initialization WITH using") { TestWithoutUsing.new }
  bm.compare!
end

# Calculating -------------------------------------
# class initialization   142.929k i/100ms
# class initialization WITH using
#                        145.323k i/100ms
# -------------------------------------------------
# class initialization      5.564M (± 8.3%) i/s -     27.728M
# class initialization WITH using
#                           5.619M (± 7.4%) i/s -     28.047M
# Comparison:
# class initialization WITH using:  5618601.3 i/s
# class initialization:  5564116.5 i/s - 1.01x slower

# Do refinements affect "normal" method lookup speed? Nope. 
Benchmark.ips do |bm|
  bm.report("run method") { TestUsing.new.noop }
  bm.report("run method in class WITH using") { TestWithoutUsing.new.noop }
  bm.compare!
end

# Calculating -------------------------------------
#           run method   141.905k i/100ms
# run method in class WITH using
#                        144.435k i/100ms
# -------------------------------------------------
#           run method      5.010M (± 6.4%) i/s -     24.975M
# run method in class WITH using
#                           5.086M (± 5.3%) i/s -     25.421M
# Comparison:
# run method in class WITH using:  5086262.3 i/s
#           run method:  5010273.6 i/s - 1.02x slower


# Is using a method from a refinement slower than using an equivalent "normal" method? Nope. 
Benchmark.ips do |bm|
  bm.report("shrug") { TestUsing.new.shrug }
  bm.report("shrug via refinement") { TestWithoutUsing.new.shrug }
  bm.compare!
end

# Calculating -------------------------------------
#                shrug    96.089k i/100ms
# shrug via refinement    95.559k i/100ms
# -------------------------------------------------
#                shrug      1.825M (± 9.3%) i/s -      9.128M
# shrug via refinement      1.929M (± 6.2%) i/s -      9.651M

# Comparison:
# shrug via refinement:  1928841.5 i/s
#                shrug:  1825069.4 i/s - 1.06x slower


# Does repeated evaluation of the `using` keyword affect performance. Only slightly. 
# This is an unfair test, but I really wanted to force refinements to be slower
# in SOME use case :)
Benchmark.ips do |bm|
  bm.report("inline shrug") { integer_to_shrugs(10) }
  bm.report("inline shrug via refinement") do
    using Shruggable
    10.shrugs
  end
  bm.compare!
end

# Calculating -------------------------------------
#         inline shrug   100.460k i/100ms
# inline shrug via refinement
#                         72.131k i/100ms
# -------------------------------------------------
#         inline shrug      2.507M (± 5.2%) i/s -     12.557M
# inline shrug via refinement
#                           1.498M (± 4.3%) i/s -      7.502M

# Comparison:
#         inline shrug:  2506663.9 i/s
# inline shrug via refinement:  1497747.6 i/s - 1.67x slower

  1. रूबी में लैम्ब्डा का उपयोग करना

    ब्लॉक रूबी का इतना महत्वपूर्ण हिस्सा हैं, उनके बिना भाषा की कल्पना करना मुश्किल है। लेकिन लैम्ब्डा? लैम्ब्डा को कौन प्यार करता है? आप एक का उपयोग किए बिना वर्षों तक जा सकते हैं। वे लगभग पुराने जमाने के अवशेष की तरह लगते हैं। ...लेकिन यह बिल्कुल सच नहीं है। एक बार जब आप उनकी थोड़ी जांच कर लेते हैं त

  1. रूबी में इंसर्शन सॉर्ट को समझना

    नोट:रूबी के साथ विभिन्न सॉर्टिंग एल्गोरिदम को लागू करने पर विचार करने वाली श्रृंखला में यह भाग 4 है। भाग 1 ने बबल सॉर्ट की खोज की, भाग 2 ने चयन प्रकार की खोज की, और भाग 3 ने मर्ज सॉर्ट की खोज की। जैसा कि हम डेटा सॉर्ट करने के लिए विभिन्न तरीकों का पता लगाना जारी रखते हैं, हम इंसर्शन सॉर्ट की ओर रु

  1. रूबी में 9 नई सुविधाएँ 2.6

    रूबी का एक नया संस्करण नई सुविधाओं और प्रदर्शन में सुधार के साथ आ रहा है। क्या आप परिवर्तनों के साथ बने रहना चाहेंगे? आइए एक नज़र डालते हैं! अंतहीन रेंज रूबी 2.5 और पुराने संस्करण पहले से ही अंतहीन श्रेणी के एक रूप का समर्थन करते हैं (Float::INFINITY के साथ) ), लेकिन रूबी 2.6 इसे अगले स्तर पर ले