लॉक स्टेटमेंट कितना महंगा है?


111

मैं मल्टी थ्रेडिंग और समानांतर प्रसंस्करण के साथ प्रयोग कर रहा हूं और मुझे प्रसंस्करण की गति की कुछ बुनियादी गिनती और सांख्यिकीय विश्लेषण करने के लिए काउंटर की आवश्यकता है। अपनी कक्षा के समवर्ती उपयोग की समस्याओं से बचने के लिए मैंने अपनी कक्षा में एक निजी चर पर लॉक स्टेटमेंट का उपयोग किया है:

private object mutex = new object();

public void Count(int amount)
{
 lock(mutex)
 {
  done += amount;
 }
}

लेकिन मैं सोच रहा था ... कितना महंगा एक चर ताला लगा रहा है? प्रदर्शन पर नकारात्मक प्रभाव क्या हैं?


10
वैरिएबल को लॉक करना इतना महंगा नहीं है; यह एक बंद चर पर इंतज़ार कर रहा है जिसे आप बचना चाहते हैं।
गाबे

53
यह एक और दौड़ की स्थिति नीचे ट्रैकिंग पर घंटे खर्च करने की तुलना में बहुत कम महंगा है ;-)
BrokenGlass

2
खैर ... अगर कोई ताला महंगा है तो आप प्रोग्रामिंग को बदलकर उनसे बचना चाह सकते हैं ताकि उसे कम ताले की जरूरत पड़े। मैं किसी प्रकार के सिंक्रनाइज़ेशन को लागू कर सकता था।
कीस सी। बक्कर

1
मेरे लॉक ब्लॉक्स से बहुत सारे कोड को स्थानांतरित करके (अभी @Gabe की टिप्पणी पढ़ने के बाद) मुझे प्रदर्शन में एक नाटकीय सुधार हुआ। निचला रेखा: अब से मैं केवल लॉक एक्सेस के अंदर केवल वैरिएबल एक्सेस (आमतौर पर एक लाइन) को छोड़ दूंगा, जैसे "टाइम लॉकिंग में"। क्या इस का कोई मतलब निकलता है?
हेलटनबीकर

2
@heltonbiker बेशक यह समझ में आता है। यह वास्तुशिल्प सिद्धांत भी होना चाहिए, आप ताले को यथासंभव छोटा, सरल और तेज बनाने वाले हैं। केवल वास्तव में आवश्यक डेटा जिसे सिंक्रनाइज़ करने की आवश्यकता है। सर्वर बॉक्स पर, आपको लॉक की हाइब्रिड प्रकृति पर भी ध्यान देना चाहिए। यदि आपके कोड के लिए महत्वपूर्ण नहीं है, तो भी ध्यान दें कि लॉक के हाइब्रिड प्रकृति के लिए धन्यवाद, प्रत्येक पहुंच के दौरान कोर को स्पिन करने के लिए यदि लॉक किसी और के पास होता है। आप प्रभावी रूप से अपने थ्रेड को निलंबित करने से पहले कुछ समय के लिए सर्वर पर अन्य सेवाओं से कुछ सीपीयू संसाधनों को खा रहे हैं।
ipavlu

जवाबों:


86

यहाँ एक लेख है जो लागत में जाता है। लघु उत्तर 50ns है।


39
लघु बेहतर जवाब: 50ns + समय प्रतीक्षा में बिताया जाता है यदि अन्य धागा ताला पकड़े हुए है।
हरमन

4
जितने अधिक धागे प्रवेश कर रहे हैं और ताला छोड़ रहे हैं, उतना ही महंगा हो जाता है। लागत धागे की संख्या के साथ तेजी से फैलती है
आर्से ज़ाहरे

16
कुछ संदर्भ: एक 3Ghz x86 पर दो संख्याओं को विभाजित करने में लगभग 10ns लगते हैं (निर्देश प्राप्त करने / डिकोड करने में लगने वाले समय को शामिल नहीं करना) ; और एक एकल चर (गैर-कैश) मेमोरी से एक रजिस्टर में लोड करने में लगभग 40ns लगते हैं। तो 50ns पागलपन की तरह है, तेजी से अंधा - आप lockएक चर का उपयोग करने की लागत के बारे में चिंता करेंगे की तुलना में किसी भी अधिक का उपयोग करने की लागत के बारे में चिंता नहीं करनी चाहिए ।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

3
साथ ही, यह लेख पुराना था जब यह प्रश्न पूछा गया था।
ओटिस

3
वास्तव में महान मीट्रिक, "लगभग कोई कीमत नहीं", गलत उल्लेख नहीं करने के लिए। आप लोग इस बात पर ध्यान न दें कि यह छोटा और तेज है और केवल तभी, जब कोई विवाद न हो, एक सूत्र। इस मामले में, आप सभी की जरूरत नहीं है। दूसरा मुद्दा, लॉक लॉक नहीं है, लेकिन हाइब्रिड लॉक है, यह सीएलआर के अंदर पता लगाता है कि परमाणु संचालन के आधार पर लॉक किसी के पास नहीं है और ऐसे मामले में, यह ऑपरेटिंग सिस्टम कोर को कॉल से बचता है, यह अलग-अलग रिंग है जो इन द्वारा मापा नहीं जाता है परीक्षण। क्या 25ns से 50ns के रूप में मापा जाता है वास्तव में आवेदन स्तर इंटरलॉक किया गया निर्देश कोड है यदि लॉक नहीं लिया गया है
ipavlu

50

तकनीकी उत्तर यह है कि यह निर्धारित करना असंभव है, यह सीपीयू मेमोरी राइट-बैक बफ़र्स की स्थिति पर निर्भर करता है और प्रीफ़ेचर को इकट्ठा करने और फिर से पढ़ने के लिए कितना डेटा एकत्र करना पड़ता है। जो दोनों बहुत ही गैर-नियतात्मक हैं। मैं 150 सीपीयू चक्रों का उपयोग बैक-ऑफ-द-लिफाफे सन्निकटन के रूप में करता हूं जो प्रमुख निराशाओं से बचा जाता है।

व्यावहारिक जवाब यह है कि यह है waaaay बार जब आप अपने कोड डिबगिंग जब आपको लगता है कि आप एक ताला को छोड़ सकते हैं पर जला देंगे की राशि की तुलना में सस्ता।

एक कठिन संख्या प्राप्त करने के लिए आपको मापना होगा। विजुअल स्टूडियो में एक एक्सटेंशन के रूप में एक सुरीला कंसीलर एनालाइजर उपलब्ध है।


1
वास्तव में नहीं, इसे मात्रा और मापा जा सकता है। यह कोड के चारों ओर उन तालों को लिखना जितना आसान नहीं है, फिर यह बताते हुए कि यह सब सिर्फ 50ns है, ताला पर एकल थ्रेडेड एक्सेस पर मापा गया एक मिथक।
4

8
"लगता है कि आप एक ताला छोड़ सकते हैं" ... मुझे लगता है कि इस सवाल को पढ़ने पर बहुत सारे लोग कहाँ हैं ...
स्नूप

30

आगे की पढाई:

मैं अपने कुछ लेख प्रस्तुत करना चाहूंगा, जो सामान्य सिंक्रोनाइज़ेशन प्राइमेटिव्स में रुचि रखते हैं और वे अलग-अलग परिदृश्यों और थ्रेड्स की संख्या के आधार पर मॉनिटर, सी # लॉक स्टेटमेंट व्यवहार, गुण और लागत में खुदाई कर रहे हैं। यह सीपीयू अपव्यय और थ्रूपुट अवधि के बारे में विशेष रूप से रुचि रखता है यह समझने के लिए कि कई परिदृश्यों में काम को कितना धक्का दिया जा सकता है:

https://www.codeproject.com/Articles/1236238/Unified-Concurrency-I-Introduction https://www.codeproject.com/Articles/1237518/Unified-Concurrency-II-benchmarker-methodologies https: // www। codeproject.com/Articles/1242156/Unified-Concurrency-III-cross-benchmarking

मूल उत्तर:

ओ प्यारे!

ऐसा लगता है कि सही उत्तर को ध्वजांकित किया गया है क्योंकि ANSWER स्वाभाविक रूप से गलत है! मैं इस लेख के लेखक से, सम्मानपूर्वक, अंत तक जुड़े हुए लेख को पढ़ना चाहता हूं। लेख

2003 के लेख के लेखक केवल दोहरे कोर मशीन पर माप कर रहे थे और पहले मापने के मामले में, उन्होंने केवल एक धागे के साथ लॉकिंग को मापा और परिणाम प्रति लॉक पहुंच के बारे में 50ns था।

यह समवर्ती वातावरण में एक ताला के बारे में कुछ नहीं कहता है। इसलिए हमें लेख पढ़ना जारी रखना है और दूसरे भाग में, लेखक दो और तीन धागों के साथ लॉकिंग परिदृश्य को माप रहा है, जो आज के प्रोसेसरों के समसामयिक स्तरों के करीब पहुंच जाता है।

तो लेखक कहता है, कि ड्यूल कोर पर दो थ्रेड्स के साथ, ताले की लागत 120ns है, और 3 थ्रेड्स के साथ यह 180ns तक जाता है। तो यह स्पष्ट रूप से ताला तक पहुँचने वाले धागे की संख्या पर निर्भर करता है।

तो यह सरल है, यह 50 एनएस नहीं है जब तक कि यह एक भी धागा न हो, जहां ताला बेकार हो जाता है।

विचार के लिए एक और मुद्दा यह है कि इसे औसत समय के रूप में मापा जाता है !

यदि पुनरावृत्तियों का समय मापा जाएगा, तो 1ms से 20ms के बीच का समय भी होगा, केवल इसलिए कि बहुमत तेज था, लेकिन कुछ थ्रेड प्रोसेसर समय की प्रतीक्षा कर रहे होंगे और यहां तक ​​कि मिलीसेकंड लंबी देरी भी होगी।

यह किसी भी तरह के आवेदन के लिए बुरी खबर है जिसमें उच्च प्रवाह, निम्न विलंबता की आवश्यकता होती है।

और विचार के लिए अंतिम मुद्दा यह है कि लॉक के अंदर धीमे संचालन हो सकते हैं और बहुत बार ऐसा ही होता है। अब कोड के ब्लॉक को लॉक के अंदर निष्पादित किया जाता है, उच्च विवाद होता है और देरी से आसमान ऊंचा हो जाता है।

कृपया विचार करें, कि 2003 से एक दशक से अधिक समय पहले ही बीत चुका है, विशेष रूप से पूरी तरह से समवर्ती रूप से चलाने के लिए डिज़ाइन किए गए प्रोसेसर की कुछ पीढ़ियां और लॉकिंग उनके प्रदर्शन को काफी नुकसान पहुंचा रहे हैं।


1
स्पष्ट करने के लिए, लेख यह नहीं कह रहा है कि लॉक प्रदर्शन एप्लिकेशन में थ्रेड्स की संख्या के साथ घटता है; प्रदर्शन लॉक के ऊपर मौजूद थ्रेड्स की संख्या के साथ घट जाता है। (जो कि उपर्युक्त उत्तर में निहित है, लेकिन स्पष्ट रूप से नहीं कहा गया है।)
गोसेबेरी

मुझे लगता है कि आप इसका मतलब यह है: "तो यह स्पष्ट रूप से समवर्ती धागे की संख्या पर निर्भर करता है और अधिक बुरा है।" हां, शब्दांकन बेहतर हो सकता है। मेरा मतलब था "समवर्ती रूप से पहुँचा हुआ" धागे के रूप में समवर्ती रूप से ताला तक पहुंच रहा है, इस प्रकार विवाद पैदा करता है।
ipavlu

20

यह प्रदर्शन के बारे में आपकी क्वेरी का उत्तर नहीं देता है, लेकिन मैं कह सकता हूं कि .NET फ्रेमवर्क एक ऐसी Interlocked.Addविधि प्रदान करता है, जो आपको किसी अन्य ऑब्जेक्ट पर मैन्युअल रूप से लॉक किए बिना amountअपने doneसदस्य को जोड़ने की अनुमति देगा ।


1
हां, यह शायद सबसे अच्छा जवाब है। लेकिन मुख्य रूप से छोटे और क्लीनर कोड के कारण। गति में अंतर ध्यान देने योग्य होने की संभावना नहीं है।
हेनक होल्टरमैन

इस उत्तर के लिए धन्यवाद। मैं ताले के साथ अधिक सामान कर रहा हूं। जोड़ा गया इन्ट्स कई में से एक है। सुझाव से प्यार करें, अब से इसका उपयोग करेंगे।
कीस सी। बक्कर

ताले सही होने के लिए बहुत आसान हैं, भले ही लॉक-फ्री कोड संभावित रूप से तेज हो। Interlocked.Add अपने आप में समान मुद्दों के साथ + = बिना किसी सिंक्रनाइज़ेशन के है।
हैंगर

10

lock (Monitor.Enter / Exit) एक वेटहैंडल या म्यूटेक्स जैसे विकल्पों की तुलना में बहुत सस्ता, सस्ता है।

लेकिन क्या होगा अगर यह (थोड़ा) धीमा था, तो क्या आपके पास गलत परिणामों के साथ एक तेज कार्यक्रम होगा?


5
हाहा ... मैं तेज कार्यक्रम और अच्छे परिणामों के लिए जा रहा था।
कीस सी। बक्कर

@ हेंक-होल्टरमैन आपके बयानों के साथ कई मुद्दे हैं: पहला जब यह प्रश्न और उत्तर स्पष्ट रूप से दिखाया गया है, समग्र प्रदर्शन पर लॉक के प्रभावों की कम समझ है, यहां तक ​​कि लोग 50 मिनट के बारे में मिथक बताते हैं जो केवल एकल-थ्रेडेड वातावरण के साथ लागू होता है। दूसरा आपका बयान यहां है और वर्षों तक रहेगा और इस बीच, कोर में विकसित प्रोसेसर, लेकिन कोर की गति इतनी अधिक नहीं होती है। ** थ्रिड ** अनुप्रयोग केवल समय के साथ अधिक जटिल हो जाते हैं, और फिर यह परत पर परत है। कई कोर के वातावरण में ताला लगा है और संख्या बढ़ रही है, 2,4,8,10,20,16,32
ipavlu

मेरा सामान्य तरीका यह है कि जितना संभव हो कम बातचीत के साथ शिथिल रूप से सिंक्रनाइज़ेशन का निर्माण किया जाए। यह बहुत तेजी से लॉक-मुक्त डेटा संरचनाओं को जाता है। मैंने विकास को सरल बनाने के लिए स्पिनकॉक के आसपास अपने कोड रैपर के लिए बनाया और यहां तक ​​कि जब टीपीएल के पास विशेष समवर्ती संग्रह हैं, तो मैंने सूची, सरणी, शब्दकोश और कतार के आसपास अपने स्वयं के स्पिन लॉक संग्रह विकसित किए हैं, क्योंकि मुझे थोड़ा और नियंत्रण चाहिए और कभी-कभी कुछ कोड के तहत चल रहा है। spinlock। मैं आपको बता सकता हूं, यह संभव है और कई परिदृश्यों को हल करने की अनुमति देता है टीपीएल संग्रह नहीं कर सकता है और महान प्रदर्शन / थ्रूपुट लाभ के साथ।
ipavlu

7

बिना लॉक वाले विकल्प की तुलना में एक तंग लूप में लॉक की लागत बहुत बड़ी है। आप कई बार लूप ले सकते हैं और फिर भी लॉक से अधिक कुशल हो सकते हैं। यही कारण है कि ताला मुक्त कतारें इतनी कुशल हैं।

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LockPerformanceConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var stopwatch = new Stopwatch();
            const int LoopCount = (int) (100 * 1e6);
            int counter = 0;

            for (int repetition = 0; repetition < 5; repetition++)
            {
                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    lock (stopwatch)
                        counter = i;
                stopwatch.Stop();
                Console.WriteLine("With lock: {0}", stopwatch.ElapsedMilliseconds);

                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    counter = i;
                stopwatch.Stop();
                Console.WriteLine("Without lock: {0}", stopwatch.ElapsedMilliseconds);
            }

            Console.ReadKey();
        }
    }
}

आउटपुट:

With lock: 2013
Without lock: 211
With lock: 2002
Without lock: 210
With lock: 1989
Without lock: 210
With lock: 1987
Without lock: 207
With lock: 1988
Without lock: 208

4
यह एक खराब उदाहरण हो सकता है क्योंकि आपका लूप वास्तव में कुछ भी नहीं करता है, एक एकल चर असाइनमेंट के अलावा और एक लॉक कम से कम 2 फ़ंक्शन कॉल है। इसके अलावा, प्रति 20ns जो आपको मिल रहा है वह उतना बुरा नहीं है।
ज़ार शारदान

5

"लागत" को परिभाषित करने के लिए कुछ अलग तरीके हैं। लॉक प्राप्त करने और जारी करने का वास्तविक ओवरहेड है; जैसा कि जेक लिखते हैं, यह नगण्य है जब तक कि यह ऑपरेशन लाखों बार किया जाता है।

अधिक प्रासंगिकता इसका प्रभाव निष्पादन के प्रवाह पर पड़ता है। यह कोड एक समय में केवल एक थ्रेड द्वारा दर्ज किया जा सकता है। यदि आपके पास नियमित रूप से इस ऑपरेशन को करने वाले 5 धागे हैं, तो उनमें से 4 को लॉक जारी होने की प्रतीक्षा में समाप्त हो जाएगा, और फिर उस लॉक के रिलीज़ होने के बाद उस कोड को दर्ज करने वाला पहला धागा होगा। तो, आपके एल्गोरिथ्म को काफी नुकसान होने वाला है। एल्गोरिथ्म पर कितना निर्भर करता है और कितनी बार ऑपरेशन कहा जाता है .. आप वास्तव में दौड़ की स्थिति को पेश किए बिना इसे टाल नहीं सकते हैं, लेकिन आप लॉक किए गए कोड पर कॉल की संख्या को कम करके इसे संशोधित कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.