কম্পিউটার

রেল কর্মক্ষমতা:কখন সঠিক পছন্দ ক্যাশ করা হয়?

প্রোগ্রামিং পরিভাষায়, ক্যাশিং বলতে বোঝায় ভবিষ্যতে দ্রুত পুনরুদ্ধারের জন্য একটি মান (বা মান) সংরক্ষণ করা। সাধারণত, আপনি এমন মানগুলির সাথে এটি করতে চান যা কিছু কারণে গণনা করতে ধীর হয়; উদাহরণস্বরূপ, তাদের পুনরুদ্ধার করার জন্য একটি বাহ্যিক API আঘাত করতে হবে, অথবা তারা তৈরি করতে প্রচুর সংখ্যা-ক্রঞ্চিং জড়িত।

ক্যাশে করা মানগুলি প্রায়ই একটি পৃথক সার্ভারে সংরক্ষণ করা হয়, যেমন মেমক্যাশেড বা রেডিস। এগুলি একটি ডিস্কে বা RAM এ সংরক্ষণ করা যেতে পারে। কোডে, আমরা অনেক সময় ব্যয়বহুল ফাংশনকে একাধিকবার কল করা এড়াতে ভেরিয়েবলের ভিতরে ডেটা 'ক্যাশে' করি।

data = some_calculation()
a(data)
b(data)

আপনি যে গতি অর্জন করছেন তার জন্য ট্রেড-অফ হল আপনি পুরানো ডেটা ব্যবহার করছেন। যদি ক্যাশে করা ডেটা 'বাসি' হয়ে যায় এবং আর সঠিক না হয়? এটিকে 'অবৈধ' করতে আপনাকে ক্যাশে সাফ করতে হবে।

ক্যাশিংয়ের বিরুদ্ধে যুক্তি

পুরানো প্রবাদ হিসাবে, কম্পিউটার বিজ্ঞানে মাত্র 2টি কঠিন সমস্যা রয়েছে:1. জিনিসের নামকরণ 2. ক্যাশে অবৈধকরণ3. একের পর এক ত্রুটি

কেন ক্যাশে অবৈধকরণ এত কঠিন? একটি ক্যাশে করা মান, তার প্রকৃতির দ্বারা, একটি বাস্তব মান 'লুকা' করে। যে কোনো সময় 'বাস্তব' মান পরিবর্তন হলে, আপনাকে (হ্যাঁ, আপনি, প্রোগ্রামারকে) ক্যাশে 'অকার্যকর' করতে মনে রাখতে হবে যাতে এটি আপডেট হয়।

ধরুন আপনি একটি পাঠ্য সম্পাদকে একটি 'শব্দ গণনা' উইজেট যোগ করছেন। ব্যবহারকারীর ধরন হিসাবে আপনাকে শব্দ সংখ্যা আপডেট করতে হবে। সহজ পদ্ধতি হল প্রতিটি কীস্ট্রোকে শব্দগুলি পুনরায় গণনা করা, তবে এটি খুব ধীর। আরেকটি পদ্ধতি আছে:

  1. ফাইল লোড করার সময় শব্দগুলি গণনা করুন।
  2. এই শব্দ-গণনাটিকে একটি ভেরিয়েবলে সংরক্ষণ করুন (বা 'ক্যাশে এটি')।
  3. ভেরিয়েবলের বিষয়বস্তু স্ক্রিনে প্রদর্শন করুন।

এই বাস্তবায়ন অনেক দ্রুত, কিন্তু ক্যাশে করা 'শব্দ গণনা' আমাদের টাইপ করার সাথে সাথে পরিবর্তন হয় না। এটি করার জন্য, যখনই আমরা শব্দ গণনা পরিবর্তনের আশা করি তখনই আমাদের ক্যাশেটিকে 'অকার্যকর' করতে হবে।

এখন, কীস্ট্রোকগুলি তৈরি হওয়ার সাথে সাথে আপনি শব্দগুলি (অর্থাৎ, স্পেস) সনাক্ত করবেন এবং কাউন্টার শব্দটি বৃদ্ধি করবেন। অবশ্যই, ব্যবহারকারী যখন শব্দগুলি মুছে ফেলবে তখন আপনি এটি হ্রাস করবেন। সহজ. সম্পন্ন. পরবর্তী টিকিট।

...কিন্তু অপেক্ষা করুন, ব্যবহারকারী যখন ক্লিপবোর্ডে পাঠ্য কাটবে তখন কি আপনি শব্দ সংখ্যা আপডেট করার কথা মনে রেখেছিলেন? তারা টেক্সট পেস্ট যখন সম্পর্কে কি? যখন বানান-পরীক্ষক একটি টাইপোকে দুটি শব্দে বিভক্ত করে তখন কী হবে?

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

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

ক্যাশিং ছাড়া গতি

যদি আমরা টেবিলের ক্যাশিং বন্ধ করে দিই, আমাদের অ্যাপ্লিকেশনের গতি বাড়ানো মানে হল পারফরম্যান্সের প্রতিবন্ধকতাগুলি সনাক্ত করা এবং ঠিক করা - সিস্টেমগুলি যা হতে পারে তার চেয়ে ধীর। আমরা তাদের তিনটি সামগ্রিক বিভাগে গ্রুপ করতে পারি:

  1. ডাটাবেস কোয়েরি (হয় খুব বেশি বা খুব ধীর)
  2. রেন্ডারিং দেখুন
  3. অ্যাপ্লিকেশন কোড (যেমন, ভারী গণনা করা)

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

প্রোফাইলিং

প্রোফাইলিং হল আপনি কিভাবে জানেন কোথায় সমস্যাগুলি আপনার অ্যাপে রয়েছে:এই পৃষ্ঠাটি কি ধীর কারণ টেমপ্লেট রেন্ডারিং ধীর? অথবা, এটি কি ধীর কারণ এটি ডাটাবেসকে মিলিয়ন বার আঘাত করছে?

রুবি অন রেলের জন্য, আমি র্যাক-মিনি-প্রোফাইলারের সুপারিশ করব, যা আপনার অ্যাপের প্রান্তে একটি সুন্দর ছোট উইজেট যোগ করে। আপনি যে পৃষ্ঠাটি দেখছেন সেটি রেন্ডার করতে এটি আপনাকে একটি ভাল ওভারভিউ দেয়, যেমন কতগুলি ডেটাবেস কোয়েরি বন্ধ করা হয়েছিল, কত সময় লেগেছিল এবং কতগুলি আংশিক রেন্ডার করা হয়েছিল৷

উৎপাদনের জন্য (প্রো-টিপ:rack-mini-profiler উত্পাদনে ভাল কাজ করে; শুধু নিশ্চিত করুন যে এটি শুধুমাত্র নির্দিষ্ট ব্যবহারকারীদের জন্য প্রদর্শিত হয়, যেমন অ্যাডমিন বা ডেভেলপার), স্কাইলাইট, নিউ রিলিক এবং স্কাউট সহ অনলাইন পরিষেবা রয়েছে, যা পৃষ্ঠার কার্যকারিতা নিরীক্ষণ করে৷

সাধারণত উদ্ধৃত লক্ষ্য <= 100ms পৃষ্ঠা রেন্ডারিংয়ের জন্য দুর্দান্ত, কারণ বাস্তব-বিশ্বের ইন্টারনেট ব্যবহারে ব্যবহারকারীর পক্ষে এর চেয়ে কম কিছু সনাক্ত করা কঠিন। আপনার লক্ষ্য অনেক কারণের উপর নির্ভর করে পরিবর্তিত হবে. এক পর্যায়ে, ভয়ানক পারফরম্যান্স সহ একটি উত্তরাধিকারী অ্যাপ্লিকেশনে কাজ করার সময়, আমি <=1 সেকেন্ড টার্গেট করেছিলাম, যা দুর্দান্ত নয় তবে আমি যখন শুরু করেছি তার চেয়ে অনেক ভাল।

বেঞ্চমার্কিং

একবার আমরা বুঝতে পারি কোথায় সমস্যা হল, তাহলে আমরা বেঞ্চমার্ক ব্যবহার করে দেখতে পারি (যদি থাকে) আমাদের অপ্টিমাইজেশন কার্যক্ষমতার উপর কী প্রভাব ফেলেছিল। ব্যক্তিগতভাবে, আমি এই ধরনের কাজের জন্য বেঞ্চমার্ক-আইপিএস রত্ন ব্যবহার করতে পছন্দ করি, কারণ এটি আপনাকে আপনার কোডের পার্থক্যগুলি দেখতে একটি সহজ মানব-পঠনযোগ্য উপায় দেয়৷

একটি তুচ্ছ উদাহরণ হিসাবে, এখানে স্ট্রিং কনক্যাটেনেশন বনাম স্ট্রিং ইন্টারপোলেশনের একটি তুলনা:

require 'benchmark/ips'

@a = "abc"
@b = "def"
Benchmark.ips do |x|
  x.report("Concatenation") { @a + @b }
  x.report("Interpolation") { "#{@a}#{@b}" }
  x.compare!
end

এবং ফলাফল:

Warming up --------------------------------------
       Concatenation   316.022k i/100ms
       Interpolation   282.422k i/100ms
Calculating -------------------------------------
       Concatenation     10.353M (± 7.4%) i/s -     51.512M in   5.016567s
       Interpolation      6.615M (± 6.8%) i/s -     33.043M in   5.023636s

Comparison:
       Concatenation: 10112435.3 i/s
       Interpolation:  6721867.3 i/s - 1.50x  slower

এটি আমাদের একটি সুন্দর মানব-পঠনযোগ্য ফলাফল দেয়, এবং ইন্টারপোলেশন সংযোগের চেয়ে 1.5 গুণ ধীর (অন্তত আমাদের ছোট স্ট্রিংগুলির জন্য)। এই কারণে, আপনি যে পদ্ধতিটি উন্নত করার চেষ্টা করছেন তা অনুলিপি করার এবং এটিকে একটি নতুন নাম দেওয়ার জন্য আমি সুপারিশ করব৷ তারপর আপনি যেতে যেতে এটির কর্মক্ষমতা উন্নত করছেন কিনা তা দেখতে আপনি দ্রুত তুলনা চালাতে পারেন।

পারফরম্যান্স সমস্যা সমাধান করা

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

ডেটাবেস কর্মক্ষমতা

ডাটাবেস-সম্পর্কিত পারফরম্যান্সের সমস্যাগুলির জন্য, কয়েকটি জিনিস দেখতে হবে। প্রথমে, ভয়ঙ্কর 'N+1 প্রশ্নগুলি' এড়িয়ে চলুন। এই ধরনের পরিস্থিতি প্রায়ই একটি ভিউতে একটি সংগ্রহ রেন্ডার করার সময় ঘটে। উদাহরণস্বরূপ, আপনার 10টি ব্লগ পোস্ট সহ একজন ব্যবহারকারী আছে এবং আপনি ব্যবহারকারী এবং তার সমস্ত পোস্ট প্রদর্শন করতে চান৷ একটি নিষ্পাপ প্রথম-কাট এই মত কিছু হতে পারে:

# Controller
def show
  @user = User.find(params[:id])
end
# View
Name: <%= @user.name %>
Posts:
  <%= @user.posts each do |post| %>
    <div>Title: <%= post.title %></div>
  <% end %>

উপরে দেখানো পদ্ধতি ব্যবহারকারীকে (1টি প্রশ্ন) পাবে এবং তারপর প্রতিটি পৃথক পোস্টের জন্য একটি ক্যোয়ারী ফায়ার করবে (N=10 কোয়েরি), যার ফলে মোট 11টি (বা N+1) হবে। সৌভাগ্যবশত, রেল .includes(:post) যোগ করে এই সমস্যার একটি সহজ সমাধান প্রদান করে আপনার ActiveRecord ক্যোয়ারীতে। সুতরাং, উপরের উদাহরণে, আমরা শুধুমাত্র নিয়ন্ত্রক কোডটি নিম্নলিখিতটিতে পরিবর্তন করি:

def show
  @user = User.includes(:post).find(params[:id])
end

এখন, আমরা ব্যবহারকারীকে আনব এবং একটি ডাটাবেস ক্যোয়ারীতে তার সব বা পোস্ট।

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

total = Model.all.map(&:somefield).sum

এটি ডাটাবেস থেকে সমস্ত রেকর্ড দখল করছে, কিন্তু মানগুলির প্রকৃত যোগফল রুবিতে ঘটে৷ আমরা ডাটাবেসকে আমাদের জন্য এইভাবে গণনা সম্পাদন করার মাধ্যমে এটিকে ত্বরান্বিত করতে পারি:

total = Model.sum(:somefield)

সম্ভবত আপনার আরও জটিল কিছু দরকার, যেমন দুটি কলাম গুণ করা:

total = Model.sum('columna * columnb')

সাধারণ ডাটাবেসগুলি এই মত মৌলিক গাণিতিক এবং যোগফল এবং গড় মত সাধারণ সমষ্টিকে সমর্থন করে, তাই map(...).sum সন্ধান করুন। আপনার কোডবেসে কল করে।

পারফর্মেন্স দেখুন

যদিও আমি বলব টেমপ্লেট-সম্পর্কিত পারফরম্যান্সের সমস্যাগুলি সমাধান হিসাবে ক্যাশিংয়ে নিজেকে আরও বেশি ধার দেয়, তবুও কিছু কম ঝুলন্ত ফল রয়েছে যা আপনি প্রথমে বাদ দিতে চাইতে পারেন৷

সাধারণ পৃষ্ঠা-লোড সময়ের জন্য, আপনি পরীক্ষা করতে পারেন যে আপনি যেকোনো জাভাস্ক্রিপ্ট বা CSS লাইব্রেরির জন্য (অন্তত প্রোডাকশন সার্ভারে) মিনিফাইড সোর্স ব্যবহার করছেন।

এছাড়াও, বিপুল সংখ্যক আংশিক অন্তর্ভুক্ত হওয়ার জন্য সতর্ক থাকুন। যদি আপনার _widget.html.erb টেমপ্লেট প্রক্রিয়া করতে 1ms লাগে, কিন্তু আপনার পৃষ্ঠায় 100টি উইজেট আছে, তাহলে এটি ইতিমধ্যে 100ms হয়ে গেছে। একটি সমাধান হল আপনার UI পুনর্বিবেচনা করা। স্ক্রীনে একবারে 100টি উইজেট থাকা সাধারণত একটি দুর্দান্ত ব্যবহারকারীর অভিজ্ঞতা নয়, এবং আপনি কিছু ফর্মের পৃষ্ঠা সংখ্যা বা, সম্ভবত, আরও কঠোর UI/UX ওভারহল ব্যবহার করে দেখতে চাইতে পারেন৷

অ্যাপ্লিকেশন কোড পারফরম্যান্স

যদি আপনার কর্মক্ষমতা সমস্যাটি ভিউ বা ডাটাবেস স্তরগুলির পরিবর্তে অ্যাপ্লিকেশন কোডে (অর্থাৎ, ডেটা ম্যানিপুলেশন) হয় তবে আপনার কাছে কয়েকটি বিকল্প রয়েছে। একটি হল অন্তত কিছু কাজ ডাটাবেসের মধ্যে পুশ করা যেতে পারে কিনা তা উপরে বর্ণিত হিসাবে, বা ডাটাবেস ভিউ হিসাবে, সম্ভবত, প্রাকৃতিক মণির মতো কিছু।

আরেকটি বিকল্প হল 'ভারী উত্তোলন'কে একটি ব্যাকগ্রাউন্ড কাজের মধ্যে স্থানান্তর করা, যদিও মানটি এখন অ্যাসিঙ্ক্রোনাসভাবে গণনা করা হচ্ছে তা পরিচালনা করার জন্য এটির জন্য আপনার UI-তে পরিবর্তনের প্রয়োজন হতে পারে।

আমার এখনও ক্যাশিং দরকার; এখন কি?

এই সবের মাধ্যমে এটি তৈরি করার পরে, আপনি হয়তো সিদ্ধান্ত নিয়েছেন যে হ্যাঁ, ক্যাশিং হল আপনার প্রয়োজনীয় সমাধান। তাহলে এখন তোমার কি করা উচিত? সাথে থাকুন কারণ রুবি অন রেলের মধ্যে উপলব্ধ বিভিন্ন ধরণের ক্যাশিং কভার করা নিবন্ধগুলির একটি সিরিজের মধ্যে এটিই প্রথম৷


  1. এন্টারপ্রাইজ ক্যাশিং কি?

  2. রুবি কেস স্টেটমেন্টের অনেক ব্যবহার

  3. আপনার রেল অ্যাপের কর্মক্ষমতা বোঝার একটি নতুন উপায়

  4. সঠিক উপায়ে কর্মক্ষমতা বাড়াতে অ্যান্ড্রয়েড ওভারক্লক করুন