एक फ़ंक्शन जो कुछ मान को स्वीकार करता है और कुछ अन्य मान लौटाता है, और फ़ंक्शन के बाहर कुछ भी परेशान नहीं करता है, इसका कोई दुष्प्रभाव नहीं है, और इसलिए यह थ्रेड-सुरक्षित है। यदि आप चीजों पर विचार करना चाहते हैं जैसे कि फ़ंक्शन कैसे निष्पादित करता है तो बिजली की खपत को प्रभावित करता है, तो यह एक अलग समस्या है।
मैं मान रहा हूँ कि आप एक ट्यूरिंग-पूर्ण मशीन की बात कर रहे हैं जो किसी प्रकार की परिभाषित प्रोग्रामिंग भाषा को क्रियान्वित कर रही है, जहाँ कार्यान्वयन विवरण अप्रासंगिक हैं। दूसरे शब्दों में, यह मायने नहीं रखता है कि स्टैक क्या कर रहा है, अगर मैं अपनी पसंद की प्रोग्रामिंग भाषा में जो फ़ंक्शन लिख रहा हूं, वह भाषा की सीमाओं के भीतर अपरिवर्तनीयता की गारंटी दे सकता है। जब मैं उच्च स्तरीय भाषा में प्रोग्रामिंग कर रहा होता हूं, तो स्टैक के बारे में नहीं सोचता, न ही मुझे ऐसा करना चाहिए।
यह समझने के लिए कि यह कैसे काम करता है, मैं C # में कुछ सरल उदाहरण प्रस्तुत करने जा रहा हूं। इन उदाहरणों के सत्य होने के लिए, हमें कुछ धारणाएँ बनानी होंगी। पहला, यह कि संकलक त्रुटि के बिना C # विनिर्देश का अनुसरण करता है, और दूसरा, यह सही कार्यक्रमों का उत्पादन करता है।
मान लें कि मैं एक साधारण फ़ंक्शन चाहता हूं जो एक स्ट्रिंग संग्रह को स्वीकार करता है, और एक स्ट्रिंग देता है जो संग्रह में सभी स्ट्रिंग्स के कॉमास द्वारा अलग किए गए का एक संयोजन है। C # में एक सरल, भोलापन लागू हो सकता है:
public string ConcatenateWithCommas(ImmutableList<string> list)
{
string result = string.Empty;
bool isFirst = false;
foreach (string s in list)
{
if (isFirst)
result += s;
else
result += ", " + s;
}
return result;
}
यह उदाहरण अपरिवर्तनीय है, प्रथम दृष्टया। मुझे इस बात की जानकारी कैसे होगी? क्योंकि string
वस्तु अपरिवर्तनीय है। हालांकि, कार्यान्वयन आदर्श नहीं है। क्योंकि result
अपरिवर्तनीय है, लूप के माध्यम से हर बार एक नई स्ट्रिंग ऑब्जेक्ट बनाई जाती है, जो मूल ऑब्जेक्ट की जगह लेती है जो result
इंगित करता है। यह गति को नकारात्मक रूप से प्रभावित कर सकता है और कचरा संग्राहक पर दबाव डाल सकता है, क्योंकि इसे उन सभी अतिरिक्त तारों को साफ करना होगा।
अब, मान लें कि मैं ऐसा करता हूं:
public string ConcatenateWithCommas(ImmutableList<string> list)
{
var result = new StringBuilder();
bool isFirst = false;
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
ध्यान दें कि मैंने string
result
एक परिवर्तनशील वस्तु के साथ प्रतिस्थापित किया है StringBuilder
। यह पहले उदाहरण की तुलना में बहुत तेज है, क्योंकि लूप के माध्यम से हर बार एक नया स्ट्रिंग नहीं बनाया जाता है। इसके बजाय, स्ट्रिंगबुलस्ट ऑब्जेक्ट केवल प्रत्येक स्ट्रिंग से वर्णों के संग्रह को जोड़ता है, और अंत में पूरी चीज को आउटपुट करता है।
क्या यह फ़ंक्शन अपरिवर्तनीय है, भले ही StringBuilder परस्पर है?
हाँ यही है। क्यूं कर? क्योंकि हर बार इस फ़ंक्शन को कॉल किया जाता है, एक नया स्ट्रिंगबुलस्टल बनाया जाता है, बस उस कॉल के लिए। इसलिए अब हमारे पास एक शुद्ध कार्य है जो थ्रेड-सुरक्षित है, लेकिन इसमें परिवर्तनशील घटक हैं।
लेकिन अगर मैंने ऐसा किया तो क्या होगा?
public class Concatenate
{
private StringBuilder result = new StringBuilder();
bool isFirst = false;
public string ConcatenateWithCommas(ImmutableList<string> list)
{
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
}
क्या यह विधि धागा-सुरक्षित है? नहीं, यह नहीं है। क्यूं कर? क्योंकि वर्ग अब राज्य धारण कर रहा है, जिस पर मेरा तरीका निर्भर करता है। एक दौड़ की स्थिति अब विधि में मौजूद है: एक धागा संशोधित हो सकता है IsFirst
, लेकिन एक और धागा पहले प्रदर्शन कर सकता है Append()
, इस स्थिति में अब मेरे पास मेरी स्ट्रिंग की शुरुआत में एक अल्पविराम है जो कि होना नहीं चाहिए।
मैं ऐसा क्यों करना चाह सकता हूं? ठीक है, मैं चाहता हूं कि धागे result
आदेश के संबंध में मेरे बिना तार को जमा कर सकते हैं , या आदेश में जो धागे आते हैं। शायद यह एक लकड़हारा है, कौन जानता है?
वैसे भी, इसे ठीक करने के लिए, मैंने lock
विधि के सराय के आसपास एक बयान दिया ।
public class Concatenate
{
private StringBuilder result = new StringBuilder();
bool isFirst = false;
private static object locker = new object();
public string AppendWithCommas(ImmutableList<string> list)
{
lock (locker)
{
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
}
}
अब यह फिर से थ्रेड-सेफ है।
एकमात्र तरीका है कि मेरे अपरिवर्तनीय तरीके संभवतः थ्रेड-सुरक्षित होने में विफल हो सकते हैं यदि विधि किसी भी तरह इसके कार्यान्वयन का हिस्सा लीक करती है। क्या ऐसा हो सकता है? नहीं तो कंपाइलर सही है और प्रोग्राम सही है। क्या मुझे कभी ऐसे तरीकों पर ताले की आवश्यकता होगी? नहीं।
इस बात के उदाहरण के लिए कि क्रियान्वयन संभवत: संक्षिप्त परिदृश्य में कैसे लीक हो सकता है, यहां देखें ।
but everything has a side effect
- उह, नहीं, यह नहीं है। एक फ़ंक्शन जो कुछ मान को स्वीकार करता है और कुछ अन्य मान लौटाता है, और फ़ंक्शन के बाहर कुछ भी परेशान नहीं करता है, इसका कोई दुष्प्रभाव नहीं है, और इसलिए यह थ्रेड-सुरक्षित है। इससे कोई फर्क नहीं पड़ता कि कंप्यूटर बिजली का उपयोग करता है। यदि आप चाहें तो हम कॉस्मिक किरणों के बारे में भी बात कर सकते हैं, जो कि मेमोरी सेल्स को मारते हैं, लेकिन तर्क को व्यावहारिक रखें। यदि आप चीजों पर विचार करना चाहते हैं कि फ़ंक्शन किस तरह से बिजली की खपत को प्रभावित करता है, तो यह थ्रेडसेफ़ प्रोग्रामिंग की तुलना में एक अलग समस्या है।