কম্পিউটার

মেমোাইজেশনের রুবিস্ট গাইড

আজ আমি কর্মক্ষমতা উন্নত করার জন্য আমার প্রিয় কৌশলগুলির একটি সম্পর্কে কথা বলতে চেয়েছিলাম। এটি একটি সহজ সামান্য পারফরম্যান্স জয়ের একটি উৎস যা অবশেষে যোগ করে, এবং শুধুমাত্র মাঝে মাঝে আপনার অ্যাপ্লিকেশনকে ধোঁয়াটে ধ্বংসস্তূপের স্তূপে কমিয়ে দেয়। শুধুমাত্র খুব মাঝে মাঝে।

এই কৌশলটিকে "স্মরণীয়করণ" বলা হয়। $10 কম্পিউটার-সায়েন্স শব্দ থাকা সত্ত্বেও, এর সহজ অর্থ হল, প্রতিবার যখন আপনি একটি মেথড কল করেন একই কাজ করার পরিবর্তে, আপনি রিটার্ন মানটিকে একটি ভেরিয়েবলে সংরক্ষণ করুন এবং পরিবর্তে এটি ব্যবহার করুন।

সিউডোকোডে এটি দেখতে কেমন তা এখানে:

def my_method
  @memo = <work> if @memo is undefined
  return @memo
end

এবং এখানে আপনি রুবি এটা কিভাবে. এটি সবচেয়ে শক্তিশালী পন্থা, কিন্তু এটি বেশ ভার্বস। অন্যান্য, আরও সংক্ষিপ্ত পদ্ধতি রয়েছে যা আমরা পরে আলোচনা করব।

class MyClass
  def my_method
    unless defined?(@my_method)
      @my_method = begin 
         # Do your calculation, database query
         # or other long-running thing here. 
      end
    end
    @my_method
  end
end

উপরের কোডটি তিনটি জিনিস করে:

  1. @my_method নামে একটি ইনস্ট্যান্স ভেরিয়েবল আছে কিনা তা পরীক্ষা করে দেখুন .
  2. যদি থাকে তবে এটি কিছু কাজ করে এবং ফলাফলটিকে @my_method এ সংরক্ষণ করে .
  3. এটি @my_method প্রদান করে

আমাদের কাছে my_method নামে একটি পদ্ধতি এবং একটি ইনস্ট্যান্স ভেরিয়েবল উভয়ই রয়েছে এই সত্যটি দ্বারা বিভ্রান্ত হবেন না . আমি আমার ভেরিয়েবলের নাম দিতে পারতাম, কিন্তু মেমোাইজ করা পদ্ধতির নামানুসারে এটির নাম রাখা প্রচলিত।

একটি শর্টহ্যান্ড সংস্করণ

উপরের কোডের সাথে একটি সমস্যা হল যে এটি কিছুটা কষ্টকর। এই কারণে, আপনি একটি শর্টহ্যান্ড সংস্করণ দেখতে পাওয়ার সম্ভাবনা অনেক বেশি যা প্রায় একই জিনিস করে:

class MyClass
  def my_method1
    @my_method1 ||= some_long_calculation
  end

  def my_method2
    @my_method2 ||= begin
      # The begin-end block lets you easily 
      # use multiple lines of code here. 
    end
  end
end

এই দুটিই রুবির a ||= b ব্যবহার করে অপারেটর, যা a || (a = b) , যা নিজেই এর জন্য কম-বেশি শর্টহ্যান্ড:

# You wouldn't use return like this in real life. 
# I'm just using it to express to beginners the idea
# that the conditional evaluates to whatever winds up in `a`.
if a
  return a
else
  a = b
  return a
end

বাগের একটি উৎস

আপনি যদি খুব ঘনিষ্ঠভাবে মনোযোগ দেন তবে আপনি লক্ষ্য করেছেন যে শর্টহ্যান্ড সংস্করণগুলি মেমো ভেরিয়েবলের অস্তিত্ব পরীক্ষা করার পরিবর্তে এর "সত্যতা" মূল্যায়ন করে। এটি শর্টহ্যান্ড সংস্করণের অন্যতম প্রধান সীমাবদ্ধতার উত্স:এটি কখনও nil মনে রাখে না অথবা false .

অনেকগুলি ব্যবহারের ক্ষেত্রে রয়েছে যেখানে এটি গুরুত্বপূর্ণ নয়। তবে এটি সেই বিরক্তিকর তথ্যগুলির মধ্যে একটি যা আপনি যখনই স্মৃতিচারণ করছেন তখন আপনাকে আপনার মনের পিছনে রাখতে হবে।

আর্গুমেন্ট সহ মনে রাখার পদ্ধতি

এখন পর্যন্ত আমরা শুধুমাত্র একক মান মেমোইজিং নিয়ে কাজ করেছি। কিন্তু অনেক ফাংশন সব সময় একই ফলাফল দেয় না। আসুন প্রযুক্তিগত সাক্ষাত্কারের একটি পুরানো পছন্দের দিকে নজর দেওয়া যাক:ফিবোনাচি সিকোয়েন্স।

আপনি রুবিতে ফিবোনাচ্চি ক্রমকে পুনরাবৃত্তভাবে গণনা করতে পারেন এভাবে:

class Fibonacci
  def self.calculate(n)
    return n if n == 0 || n == 1
    calculate(n - 1) + calculate(n - 2)
  end
end

Fibonacci.calculate(10) # => 55

এই বাস্তবায়নের সমস্যা হল এটি অদক্ষ। এটি প্রমাণ করতে, আসুন একটি print যোগ করি n এর মান দেখার বিবৃতি .

class Fibonacci
  def self.calculate(n)
    print "#{ n } "
    return n if n == 0 || n == 1
    calculate(n - 1) + calculate(n - 2)
  end
end

Fibonacci.calculate(4)

# Outputs: 4 3 2 1 0 1 2 1 0

আপনি দেখতে পাচ্ছেন, calculate n এর একই মানগুলির সাথে বারবার কল করা হচ্ছে . আসলে calculate করতে কলের সংখ্যা n এর সাথে দ্রুতগতিতে বৃদ্ধি পেতে চলেছে৷ .

এর চারপাশে একটি উপায় হল calculate এর ফলাফলগুলি মনে রাখা . এটি করা আমাদের কভার করা অন্যান্য মেমোাইজেশন উদাহরণ থেকে খুব আলাদা নয়।

class Fibonacci
  def self.calculate(n)
    @calculate ||= {}
    @calculate[n] ||= begin
      print "#{ n } "
      if n == 0 || n == 1
        n
      else
        calculate(n - 1) + calculate(n - 2)
      end
    end
  end
end

Fibonacci.calculate(4)

# Outputs: 4 3 2 1 0

এখন আমরা calculate মুখস্থ করেছি , n দিয়ে কলের সংখ্যা আর দ্রুতগতিতে বাড়ে না .

Fibonacci.calculate(20)

# Outputs: 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

অবৈধতা

মেমোাইজেশন অনেকটা ক্যাশিংয়ের মতোই, মেমোাইজ করা ফলাফলগুলি স্বয়ংক্রিয়ভাবে মেয়াদ শেষ হয় না, এবং সেট করার পরে সেগুলি পরিষ্কার করার সহজ উপায় নেই।

ফিবোনাচি সিকোয়েন্স জেনারেটরের মতো ব্যবহারের ক্ষেত্রে এটি খুব কমই গুরুত্বপূর্ণ। Fibonacci.calculate(10) সবসময় একই ফলাফল ফিরে আসবে। কিন্তু অন্যান্য ব্যবহারের ক্ষেত্রে এটি গুরুত্বপূর্ণ।

উদাহরণস্বরূপ, আপনি এইরকম কোড দেখতে পারেন:

# Not the best idea
class User
  def full_name
    @full_name ||= [first_name, last_name].join(" ")
  end
end

ব্যক্তিগতভাবে, আমি এখানে মেমোাইজেশন ব্যবহার করব না কারণ যদি প্রথম বা শেষ নাম পরিবর্তন করা হয়, তাহলে পুরো নাম আপডেট নাও হতে পারে।

একটি জায়গা যেখানে আপনি একটু বেশি শিথিল হতে পারেন তা হল রেল কন্ট্রোলারের ভিতরে। এইরকম কোড দেখা খুবই সাধারণ:

class ApplicationController
  def current_user
    @current_user ||= User.find(...)
  end
end

এটি ঠিক আছে, কারণ প্রতিটি ওয়েব অনুরোধের পরে কন্ট্রোলার ইনস্ট্যান্সটি ধ্বংস হয়ে যায়। এটি অসম্ভাব্য যে বর্তমানে লগ-ইন করা ব্যবহারকারী যেকোনো স্বাভাবিক অনুরোধের সময় পরিবর্তিত হবে।

অ্যাকশনকেবলের মতো স্ট্রিমিং সংযোগগুলির সাথে কাজ করার সময় আপনাকে আরও সতর্ক হতে হবে। আমি জানি না আমি এটা ব্যবহার করিনি.

অতিব্যবহার

পরিশেষে আমি মনে করি যে আমার উল্লেখ করা উচিত যে যেকোন কিছুর মতো, স্মৃতিকরণকে অনেক দূরে নিয়ে যাওয়া সম্ভব। এটি এমন একটি কৌশল যা সত্যিই শুধুমাত্র ব্যয়বহুল ক্রিয়াকলাপের ক্ষেত্রে প্রয়োগ করা উচিত যা মেমো ভেরিয়েবলের সারাজীবনে কখনই পরিবর্তন হবে না।


  1. Btrfs-এর জন্য দ্য বিগিনারস গাইড

  2. পরিবেশের ভেরিয়েবলের জন্য রুবিস্ট গাইড

  3. ইনপুট ও আউটপুট (IO) রুবিতে:দ্য ডেফিনিটিভ গাইড

  4. ম্যাক নিরাপত্তা:অপরিহার্য গাইড