কম্পিউটার টিউটোরিয়াল

রুবি রিফাইনমেন্ট পারফরম্যান্স অ্যানালাইসিস: বেঞ্চмар্ক এবং ইনসাইট

আপনি যদি গুগলে রুবি রিফাইনমেন্ট সার্চ করেন ব্যাক স্টোরি না জেনে, তবে আপনি ভাবতে পারেন রিফাইনমেন্ট স্লো।

যেভাবে আসল প্রস্তাবনা ছিল, সেটি অনুযায়ী রিফাইনমেন্ট স্লো হতো। সেটি ইন্টারপ্রেটারকে মেথড লুকআপের মতো অপ্টিমাইজেশন করতে অক্ষম করত।

কিন্তু রিফাইনমেন্টের আসল ইমপ্লিমেন্টেশন আসল প্রস্তাবের চেয়ে কিছুটা সীমাবদ্ধ। তাই মনে হয়লো আজ রুবিতে বিদ্যমান রিফাইনমেন্টের ওপর একটি সিরিজ বেঞ্চмар্ক চালাতে रोচক হবে।

TL;DR

রিফাইনমেন্ট স্লো নয়। অথবা কমপক্ষে সেগুলো "নরমাল" মেথড থেকে কোনো স্লোওর দেখাচ্ছে না।

ডামি লোড

আমরা মেথড কল বেঞ্চмар্ক করব। তাই আমাদের কিছু মেথড লাগবে।

এখানে, আমি একটি বোকামি ছোট মেথডের দুটি ভার্সন তৈরি করছি। একটি "নরমাল" এবং অন্যটি একটি রিফinement-এ:

# আমাদের "ডামি লোড" হিসেবে shruggs তৈরি করব।
# 1 shrug == "¯\_(ツ)_/¯"
# 2 shrugs == "¯\_(ツ)_/¯¯\_(ツ)_/¯"
# ...etc.
SHRUG = "¯\_(ツ)_/¯"

# একটি রিফাইনমেন্ট তৈরি করব যা shruggs জেনারেট করে
module Shruggable
  refine Fixnum do
    def shrugs
      SHRUG * self
    end
  end
end

# ...এবং একটি নরমাল মেথড তৈরি করব যা শুধু shruggs জেনারেট করে
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

বেঞ্চمار্ক

আমি জানতে চাইলে রিফাইনমেন্ট ব্যবহার করে অবজেক্ট ইনস্ট্যানশিয়েট করা কি স্লোওর, অথবা রিফাইনমেন্ট দিয়ে যোগ করা মেথড কল করা কি স্লোওর।

সभी বেঞ্চমার্ক MRI 2.2.2-এ OSX El Capitan-এ চালানো হয়েছে।

অবজেক্ট ক্রিয়েশন

"using" কিওয়ার্ড কি একটি ক্লাসকে স্লোওর করে ইনিশিয়ালাইজ? না।

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

ডেক স্ট্যাকিং

আমি কি কিছু করতে পারি যাতে রিফাইনমেন্ট বেঞ্চমার্ক আমার কন্ট্রোল থেকে স্লোওর হয়? ¯\_(ツ)_/¯

# কি `using` কিওয়ার্ডের রিপিটেড ইভ্যালুয়েশন পারফরম্যান্সকে প্রভাবিত করে। কয়েকটু।
# এটি একটি অনফেয়ার টেস্ট, কিন্তু আমি চেस्टাম রিফাইনমেন্টকে কিছু ইউজ কেসে স্লোওর করার জন্য :)
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
# 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
# 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
# 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
  1. রুবিতে বিটওয়াইজ অপারেশন মাস্টার করুন: টিপস অ্যান্ড ট্রিকস

  2. রুবিতে ল্যাম্বডা মাস্টার করুন: বেসিক থেকে অ্যাডভান্সড টেকনিক

  3. রুবি দিয়ে ইন্সারশন সর্টিং দক্ষতা অর্জন: ধাপে ধাপে গাইড

  4. রুবি ২.৬-এ ৯টি গুরুত্বপূর্ণ উন্নতির অন্বেষণ