মূল ডেটা স্ট্রাকচারগুলির কোনওটিই থ্রেড নিরাপদ নয়। রুবীর সাথে যে জাহাজগুলি সম্পর্কে আমি কেবল জানি তা হ'ল স্ট্যান্ডার্ড লাইব্রেরি ( require 'thread'; q = Queue.new
) -এর সারি বাস্তবায়ন ।
এমআরআইয়ের জিআইএল থ্রেড সুরক্ষা সমস্যা থেকে আমাদের বাঁচায় না। এটি কেবল নিশ্চিত করে যে দুটি থ্রেড একই সাথে রুবি কোড চালাতে পারে না , অর্থাত্ একই সময়ে দুটি পৃথক সিপিইউতে। আপনার কোডের যে কোনও পয়েন্টে থ্রেডগুলি এখনও বিরতি দেওয়া এবং পুনরায় শুরু করা যেতে পারে। আপনি যদি @n = 0; 3.times { Thread.start { 100.times { @n += 1 } } }
একাধিক থ্রেড থেকে ভাগ করা ভেরিয়েবলকে রূপান্তর করার মতো কোড লিখেন তবে ভাগ করে নেওয়া ভেরিয়েবলের মান পরে নির্ধারক নয়। জিআইএল কম-বেশি একটি একক কোর সিস্টেমের অনুকরণ, এটি সঠিক সমবর্তী প্রোগ্রামগুলি লেখার মৌলিক বিষয়গুলিকে পরিবর্তন করে না।
এমনকি এমআরআই যদি নোড.জেএস এর মতো একক থ্রেডযুক্ত হয়ে থাকে তবে আপনার এখনও সম্মতি সম্পর্কে চিন্তা করতে হবে। বর্ধিত ভেরিয়েবলের উদাহরণটি সূক্ষ্মভাবে কাজ করবে তবে আপনি এখনও রেস শর্ত পেতে পারেন যেখানে জিনিসগুলি অ-নিরস্তিক ক্রমে ঘটে এবং একটি কলব্যাক ক্লোবার অন্যের ফলাফল। একক থ্রেডযুক্ত অ্যাসিনক্রোনাস সিস্টেমগুলি সম্পর্কে বিতর্ক করা সহজ, তবে তারা সম্মতিযুক্ত ইস্যু থেকে মুক্ত নয়। একাধিক ব্যবহারকারীর সাথে কেবল একটি অ্যাপ্লিকেশনটির কথা চিন্তা করুন: যদি দু'জন ব্যবহারকারী একই সময়ে কম-বেশি স্ট্যাক ওভারফ্লো পোস্টে সম্পাদনা সম্পাদনা করেন, পোস্ট সম্পাদনায় কিছুটা সময় ব্যয় করুন এবং তারপরে সংরক্ষণ করুন, যার পরিবর্তনগুলি পরে তৃতীয় ব্যবহারকারী দেখবেন একই পোস্ট পড়ুন?
রুবিতে, অন্যান্য সাম্প্রতিক রানটাইমের মতো, একের অধিক ক্রিয়াকলাপ থ্রেড নিরাপদ নয়। @n += 1
থ্রেড নিরাপদ নয়, কারণ এটি একাধিক অপারেশন। @n = 1
থ্রেডটি নিরাপদ কারণ এটি একটি অপারেশন (এটি হুডের অধীনে প্রচুর অপারেশন, এবং আমি সম্ভবত এটি "থ্রেড নিরাপদ" কেন বিশদটি বর্ণনা করার চেষ্টা করেছি তবে শেষ পর্যন্ত আপনি কার্যনির্বাহী থেকে অসামঞ্জস্যপূর্ণ ফলাফল পাবেন না )। @n ||= 1
, না এবং অন্য কোনও শর্টহ্যান্ড অপারেশন + অ্যাসাইনমেন্ট হয়। একটি ভুল যা আমি বহুবার করেছি তা হ'ল লেখা return unless @started; @started = true
, যা মোটেই থ্রেড নিরাপদ নয়।
আমি রুবির পক্ষে থ্রেড নিরাপদ এবং নন-থ্রেড নিরাপদ বিবৃতিগুলির কোনও অনুমোদনের তালিকা জানি না, তবে থাম্বের একটি সহজ নিয়ম রয়েছে: যদি কোনও অভিব্যক্তি কেবল একটি (পার্শ্ব-প্রভাব মুক্ত) অপারেশন করে তবে এটি সম্ভবত থ্রেড নিরাপদ। উদাহরণস্বরূপ: a + b
ঠিক আছে, a = b
এটিও ঠিক আছে, এবং a.foo(b)
ঠিক আছে, যদি পদ্ধতিটি foo
পার্শ্ব-প্রতিক্রিয়া মুক্ত থাকে (যেহেতু রুবির কোনও কিছুই একটি মেথড কল, এমনকি অনেক ক্ষেত্রে অ্যাসাইনমেন্ট, এটি অন্যান্য উদাহরণগুলির ক্ষেত্রেও যায়)। এই প্রসঙ্গে পার্শ্ব-প্রতিক্রিয়া মানে এমন জিনিস যা রাষ্ট্র পরিবর্তন করে। def foo(x); @x = x; end
হয় না পার্শ্ব প্রতিক্রিয়া বিনামূল্যে।
রুবিতে থ্রেড নিরাপদ কোড লেখার বিষয়ে একটি কঠিন বিষয় হ'ল অ্যারে, হ্যাশ এবং স্ট্রিং সহ সমস্ত মূল ডেটা স্ট্রাকচার পরিবর্তনযোগ্য। দুর্ঘটনাক্রমে আপনার রাজ্যের একটি অংশ ফাঁস করা খুব সহজ, এবং যখন সেই অংশটি পরিবর্তনযোগ্য জিনিসগুলি সত্যিই খারাপ হয়ে যায়। নিম্নলিখিত কোড বিবেচনা করুন:
class Thing
attr_reader :stuff
def initialize(initial_stuff)
@stuff = initial_stuff
@state_lock = Mutex.new
end
def add(item)
@state_lock.synchronize do
@stuff << item
end
end
end
এই শ্রেণীর একটি উদাহরণ থ্রেডের মধ্যে ভাগ করা যায় এবং তারা নিরাপদে এতে জিনিস যুক্ত করতে পারে তবে একটি কনসারুঞ্চি বাগ আছে (এটি একমাত্র নয়) stuff
অ্যাক্সেসরের মাধ্যমে অবজেক্টের অভ্যন্তরীণ অবস্থা ফাঁস হয় । এনক্যাপসুলেশন দৃষ্টিকোণ থেকে সমস্যাযুক্ত হওয়ার পাশাপাশি এটি সম্মতিযুক্ত কৃমিগুলির একটি ক্যানও খোলে। হতে পারে যে কেউ অ্যারে নিয়ে যায় এবং এটিকে অন্য কোথাও পৌঁছে দেয় এবং সেই কোডটি পরিবর্তিতভাবে মনে করে যে এটি এখন সেই অ্যারের মালিক এবং এটি যা চায় তা করতে পারে।
আর একটি ক্লাসিক রুবির উদাহরণ হ'ল:
STANDARD_OPTIONS = {:color => 'red', :count => 10}
def find_stuff
@some_service.load_things('stuff', STANDARD_OPTIONS)
end
find_stuff
এটি ব্যবহৃত প্রথমবারে ঠিকঠাক কাজ করে তবে দ্বিতীয়বারের মতো অন্য কিছু দেয়। কেন? load_things
পদ্ধতি এটা পাস অপশন হ্যাশ মালিক, এবং আছে মনে ঘটবে color = options.delete(:color)
। এখন STANDARD_OPTIONS
ধ্রুবকের আর মান হয় না। ধ্রুবকরা কেবল তারা যা উল্লেখ করে তাতে স্থির থাকে, তারা যে ডেটা কাঠামোকে উল্লেখ করেছে তার স্থায়িত্বের গ্যারান্টি দেয় না। এই কোডটি একই সাথে চালানো হলে কী হবে তা ভেবে দেখুন।
যদি আপনি ভাগ করা মিউটਟੇবল অবস্থা (উদাহরণস্বরূপ একাধিক থ্রেড দ্বারা অ্যাক্সেস করা অবজেক্টগুলিতে উদাহরণের ভেরিয়েবলগুলি, একাধিক থ্রেড দ্বারা অ্যাক্সেস করা হ্যাশ এবং অ্যারে জাতীয় ডেটা স্ট্রাকচার) এড়িয়ে যান তবে থ্রেড সুরক্ষা এতটা কঠিন নয়। একযোগে অ্যাক্সেস করা আপনার আবেদনের অংশগুলি ছোট করার চেষ্টা করুন এবং সেখানে আপনার প্রচেষ্টা ফোকাস করুন। আইআইআরসি, একটি রেলস অ্যাপ্লিকেশনটিতে, প্রতিটি অনুরোধের জন্য একটি নতুন নিয়ামক বস্তু তৈরি করা হয়, সুতরাং এটি কেবলমাত্র একটি একক থ্রেড দ্বারা ব্যবহৃত হতে চলেছে এবং আপনি সেই নিয়ামক থেকে তৈরি কোনও মডেল অবজেক্টের ক্ষেত্রেও একই কাজ করতে পারেন। তবে, রেলগুলি গ্লোবাল ভেরিয়েবলের ব্যবহারকেও উত্সাহ দেয় (গ্লোবাল ভেরিয়েবল User.find(...)
ব্যবহার করে)User
, আপনি এটিকে কেবল একটি শ্রেণি হিসাবে মনে করতে পারেন, এবং এটি একটি শ্রেণি, তবে এটি বৈশ্বিক পরিবর্তনশীলগুলির একটি নেমস্পেস), এর মধ্যে কিছুগুলি নিরাপদ কারণ তারা কেবল পঠিত হয়, তবে কখনও কখনও আপনি এই বৈশ্বিক পরিবর্তনশীলগুলিতে জিনিসগুলি সংরক্ষণ করেন কারণ এটি সুবিধাজনক আপনি বিশ্বব্যাপী অ্যাক্সেসযোগ্য যে কোনও কিছু ব্যবহার করার সময় খুব সাবধান হন।
থ্রেডেড পরিবেশে রেলগুলি চালানো এখন বেশ কিছুক্ষণ সম্ভব হয়েছে, সুতরাং রেল বিশেষজ্ঞ না হয়ে আমি এখনও এতদূর যেতে পারি যে এটি যখন নিজেই রেলের কাছে আসে তখন আপনাকে থ্রেড সুরক্ষার জন্য কোনও চিন্তা করতে হবে না। আপনি উপরে উল্লিখিত কিছু কাজ করে এখনও সুরক্ষিত অ্যাপ্লিকেশন তৈরি করতে পারেন যা থ্রেড নিরাপদ নয়। যখন এটি আসে অন্য রত্নগুলি ধরে নেয় যে তারা থ্রেড নিরাপদে নেই যতক্ষণ না তারা বলে যে তারা তারা, এবং যদি তারা বলে যে তারা ধরে নিচ্ছে যে তারা নয় তবে তাদের কোডটি দেখুন (তবে কেবল আপনি দেখতে পাচ্ছেন যে তারা এ জাতীয় জিনিসগুলিতে চলেছে)@n ||= 1
এর অর্থ এই নয় যে তারা থ্রেড নিরাপদ নয়, এটি সঠিক প্রসঙ্গে একটি উপযুক্ত বৈধ জিনিস - আপনার পরিবর্তে বৈশ্বিক পরিবর্তনশীলগুলিতে পরিবর্তনীয় রাষ্ট্রের মতো জিনিসগুলির সন্ধান করা উচিত, এটি কীভাবে পরিবর্তিত পদার্থকে তার পদ্ধতিগুলিতে পরিচালিত করে এবং বিশেষত কীভাবে এটি পরিচালনা করে অপশন হ্যাশগুলি পরিচালনা করে)।
অবশেষে, থ্রেড অনিরাপদ হওয়া একটি ট্রানজিটিভ সম্পত্তি। থ্রেড নিরাপদ নয় এমন কিছু ব্যবহার করে তা নিজেই থ্রেড নিরাপদ নয়।