मैं लॉक-फ्री तकनीकों के बारे में पढ़ रहा हूं, जैसे तुलना-और-स्वैप और लॉकिंग के बिना थ्रेड सिंक्रनाइज़ेशन प्राप्त करने के लिए इंटरलाक्ड और स्पिनवाइट कक्षाओं का लाभ उठाना।लॉक्स बनाम तुलना-और-स्वैप
मैंने अपने स्वयं के कुछ परीक्षण चलाए हैं, जहां मेरे पास बस एक स्ट्रिंग में एक चरित्र को जोड़ने की कोशिश कर रहे कई धागे हैं। मैंने नियमित lock
एस और तुलना-और-स्वैप का उपयोग करने का प्रयास किया। आश्चर्य की बात है (कम से कम मेरे लिए), ताले सीएएस का उपयोग करने से बेहतर परिणाम दिखाते हैं।
यहां मेरे कोड का सीएएस संस्करण है (this पर आधारित)।
private string _str = "";
public void Append(char value)
{
var spin = new SpinWait();
while (true)
{
var original = Interlocked.CompareExchange(ref _str, null, null);
var newString = original + value;
if (Interlocked.CompareExchange(ref _str, newString, original) == original)
break;
spin.SpinOnce();
}
}
और सरल (और अधिक कुशल) ताला संस्करण:
private object lk = new object();
public void AppendLock(char value)
{
lock (lk)
{
_str += value;
}
}
तो मैं 50.000 वर्णों को जोड़ने का प्रयास करते हैं, कैस संस्करण 1.2 सेकंड लेता है यह एक copy-> संशोधित> स्वैप पद्धति का अनुसरण और लॉक संस्करण 700ms (औसत)। 100k वर्णों के लिए, क्रमश: 7 सेकंड और 3.8 सेकंड लेते हैं। यह क्वाड-कोर (i5 2500k) पर चलाया गया था।
मुझे संदेह है कि क्यों सीएएस इन परिणामों को प्रदर्शित कर रहा था क्योंकि यह आखिरी "स्वैप" कदम को विफल कर रहा था। मैं सही था। जब मैं 50k वर्ण (50k सफल स्वैप) जोड़ने का प्रयास करता हूं, तो मैं 70k (सर्वोत्तम केस परिदृश्य) और लगभग 200k (सबसे खराब केस परिदृश्य) विफल प्रयासों के बीच गिनने में सक्षम था। सबसे खराब स्थिति परिदृश्य, हर 5 प्रयासों में से 4 विफल रहा।
तो मेरी प्रश्न हैं:
- मैं क्या याद आ रही है? सीएएस बेहतर परिणाम नहीं देना चाहिए? लाभ कहां है?
- सीएएस एक बेहतर विकल्प क्यों और कब है? (मुझे पता है कि यह पूछा गया है, लेकिन मुझे कोई संतोषजनक उत्तर नहीं मिल रहा है जो मेरे विशिष्ट परिदृश्य को भी समझाता है)।
यह मेरी समझ है कि रोजगार समाधान कैस है, हालांकि कोड के लिए कड़ी मेहनत, ज्यादा बेहतर पैमाने पर और विवाद बढ़ने के साथ ताले की तुलना में बेहतर प्रदर्शन करते हैं। मेरे उदाहरण में, ऑपरेशन बहुत छोटे और लगातार होते हैं, जिसका अर्थ है उच्च विवाद और उच्च आवृत्ति। तो मेरे परीक्षण अन्यथा क्यों दिखाते हैं?
मुझे लगता है कि लंबे परिचालन मामले को और भी बदतर बना देंगे -> "स्वैप" असफल दर और भी बढ़ेगी।
पुनश्च:
Stopwatch watch = Stopwatch.StartNew();
var cl = new Class1();
Parallel.For(0, 50000, i => cl.Append('a'));
var time = watch.Elapsed;
Debug.WriteLine(time.TotalMilliseconds);
नहीं, आप सीएएस के निष्पादन समय को मापते नहीं हैं, लेकिन ज्यादातर स्ट्रिंग की निष्पादन समय की तुलना करते हैं। दुर्भाग्यवश इंटरलाक्ड क्लास में संदर्भ प्रकारों के लिए परमाणु रीड-संशोधित-लेखन ऑपरेशन नहीं है (यही वह है जो आप मूल रूप से स्ट्रिंग तुलनाओं पर भरोसा किए बिना अपने "लॉक" उदाहरण में कर रहे हैं।) – elgonzo
आपका लॉक फ्री समाधान लॉक से अधिक काम कर रहा है संस्करण। सबसे पहले, मौजूदा मान को पढ़ने के लिए प्रारंभिक 'तुलना एक्सचेंज' ओवरकिल है, अस्थिर पढ़ने ('थ्रेड। वोलाटाइल रीड ') करने से आपको कम ओवरहेड के बिना एक ही परिणाम मिल जाएगा। दूसरा, लूप के भीतर प्रत्येक प्रयास किए गए अपडेट स्ट्रिंग के "वर्तमान" मान को डुप्लिकेट करेंगे और नए मान जोड़ देंगे। आप इसके बारे में कुछ भी नहीं कर सकते हैं, लेकिन लॉक संस्करण इस समस्या से पीड़ित नहीं है। यह स्ट्रिंग प्रति है जो अधिकतर समय के अंतर के कारण होने की संभावना है। – William
हमारे लिए केवल प्राणियों, अपने आप को रोल करने की कोशिश करने के बजाय मौजूदा ताले का उपयोग करने के साथ चिपके रहें। [एबीए] (http://en.wikipedia.org/wiki/ABA_problem) समस्याओं से निपटने के बिना मल्टीथ्रेडिंग काफी कठिन है। – William