काउंटडाउनचैट बनाम सेमाफोर


92

क्या उपयोग करने का कोई फायदा है

java.util.concurrent.CountdownLatch

के बजाय

java.util.concurrent.Semaphore ?

जहाँ तक मैं बता सकता हूँ निम्नलिखित टुकड़े लगभग बराबर हैं:

1. सेमफोर

final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        sem.release();
      }
    }
  };
  t.start();
}

sem.acquire(num_threads);

2: CountDownLatch

final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        latch.countDown();
      }
    }
  };
  t.start();
}

latch.await();

सिवाय इसके कि # 2 के मामले में कुंडी का पुन: उपयोग नहीं किया जा सकता है और इससे भी महत्वपूर्ण बात यह है कि आपको अग्रिम में यह जानना होगा कि कितने धागे बनाए जाएंगे (या जब तक वे कुंडी बनाने से पहले शुरू नहीं हो जाते, तब तक प्रतीक्षा करें।)

तो किस स्थिति में कुंडी बेहतर हो सकती है?

जवाबों:


109

काउंटडाउन कुंडी अक्सर आपके उदाहरण के ठीक विपरीत के लिए उपयोग की जाती है। आम तौर पर, आपके पास "प्रतीक्षा" () पर अवरुद्ध होने वाले कई धागे होते हैं जो काउंटाउन शून्य तक पहुंचने पर सभी एक साथ शुरू होंगे।

final CountDownLatch countdown = new CountDownLatch(1);
for (int i = 0; i < 10; ++ i){
   Thread racecar = new Thread() {    
      public void run()    {
         countdown.await(); //all threads waiting
         System.out.println("Vroom!");
      }
   };
   racecar.start();
}
System.out.println("Go");
countdown.countDown();   //all threads start now!

आप इसे MPI- स्टाइल "बैरियर" के रूप में भी उपयोग कर सकते हैं, जिससे सभी धागे आगे बढ़ने से पहले एक निश्चित बिंदु तक अन्य थ्रेड्स को पकड़ने के लिए प्रतीक्षा करते हैं।

final CountDownLatch countdown = new CountDownLatch(num_thread);
for (int i = 0; i < num_thread; ++ i){
   Thread t= new Thread() {    
      public void run()    {
         doSomething();
         countdown.countDown();
         System.out.printf("Waiting on %d other threads.",countdown.getCount());
         countdown.await();     //waits until everyone reaches this point
         finish();
      }
   };
   t.start();
}

उस सभी ने कहा, काउंटडाउन कुंडी सुरक्षित रूप से आपके उदाहरण में दिखाए गए तरीके से उपयोग की जा सकती है।


1
धन्यवाद। तो मेरे दो उदाहरण समतुल्य नहीं होंगे यदि कई धागे कुंडी पर प्रतीक्षा कर सकते हैं ... जब तक कि sem.acquire (num_threads); इसके बाद sem.release (num_threads) ;? मुझे लगता है कि यह उन्हें फिर से समकक्ष बना देगा।
फाइननव

एक अर्थ में, हाँ, जब तक कि प्रत्येक थ्रेड को अधिग्रहण के बाद रिलीज कहा जाता है। सख्ती से बोलना, नहीं। एक कुंडी के साथ, सभी धागे एक साथ शुरू करने के लिए पात्र हैं। सेमाफोर के साथ, वे एक के बाद एक पात्र बन जाते हैं (जिसके परिणामस्वरूप अलग-अलग सूत्र निर्धारण हो सकते हैं)।
जेम्स स्कैच

जावा प्रलेखन का अर्थ है कि यह काउंटडाउनचैट उनके उदाहरण के साथ अच्छी तरह से फिट बैठता है: docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/… । विशेष रूप से, "एन की गणना की गई एक काउंटडाउनचैच का उपयोग एक धागा प्रतीक्षा करने के लिए किया जा सकता है जब तक कि एन थ्रेड्स ने कुछ कार्रवाई पूरी नहीं की है, या कुछ एक्शन एन बार पूरा हो चुका है।"
क्रिस मॉरिस

तुम सही हो। मैं अपने उत्तर को थोड़ा सा अपडेट करके दिखाऊंगा कि यह काउंटडाउनचैच का सबसे आम उपयोग है जो मैंने बनाम देखा है कि यह इच्छित उपयोग है।
जेम्स स्कैच

11
यह इस सवाल का जवाब देता है कि काउंटडाउनचैच का सबसे अधिक उपयोग क्या है? यह सेमाफोर पर काउंटडाउनचैच का उपयोग करने के फायदे / अंतर के बारे में मूल प्रश्न का उत्तर नहीं देता है।
मार्को Lackovic

67

काउंटडाउनचैट का उपयोग थ्रेड्स की एक श्रृंखला शुरू करने के लिए किया जाता है और तब तक प्रतीक्षा करें जब तक कि सभी पूर्ण न हो जाएं (या जब तक वे countDown()किसी दिए गए नंबर पर कॉल न करें ।

एक संसाधन का उपयोग करने वाले समवर्ती धागे की संख्या को नियंत्रित करने के लिए सेमाफोर का उपयोग किया जाता है। वह संसाधन फ़ाइल की तरह कुछ हो सकता है, या थ्रेड को निष्पादित करने की संख्या को सीमित करके सीपीयू हो सकता है। एक सेमाफोर पर गिनती ऊपर जाना और नीचे अलग धागे फोन के रूप में कर सकते हैं acquire()और release()

अपने उदाहरण में, आप अनिवार्य रूप से सेमाफोर का उपयोग काउंट यूपी लैच के एक प्रकार के रूप में कर रहे हैं । यह देखते हुए कि आपका इरादा सभी धागों के परिष्करण पर इंतजार करना है, CountdownLatchआपके इरादे को स्पष्ट करता है।


22

संक्षिप्त सारांश:

  1. सेमफोर और काउंटडाउनचैच अलग उद्देश्य प्रदान करता है।

  2. संसाधन तक थ्रेड पहुंच को नियंत्रित करने के लिए सेमाफोर का उपयोग करें ।

  3. सभी थ्रेड के पूरा होने की प्रतीक्षा करने के लिए CountDownLatch का उपयोग करें

जेवाडोक से सेमाफोर परिभाषा:

एक सेमाफोर परमिट का एक सेट रखता है। यदि कोई परमिट उपलब्ध है, तो प्रत्येक अधिग्रहण () ब्लॉक करता है और फिर इसे लेता है। प्रत्येक रिलीज़ () एक परमिट जोड़ता है, संभावित रूप से एक अवरुद्ध अधिग्रहणकर्ता को जारी करता है।

हालाँकि, कोई वास्तविक परमिट ऑब्जेक्ट का उपयोग नहीं किया जाता है; सेमाफोर सिर्फ संख्या की गिनती उपलब्ध रहता है और उसके अनुसार कार्य करता है।

यह कैसे काम करता है ?

Semaphores का उपयोग समवर्ती थ्रेड्स की संख्या को नियंत्रित करने के लिए किया जाता है जो एक संसाधन का उपयोग कर रहे हैं। संसाधन किसी साझा डेटा या कोड ( महत्वपूर्ण अनुभाग ) या किसी फ़ाइल का एक ब्लॉक जैसा कुछ हो सकता है ।

एक सेमाफोर पर गिनती अलग-अलग धागे कॉल acquire() और release() के रूप में ऊपर और नीचे जा सकती है । लेकिन किसी भी समय, आपके पास सेमाफोर गणना से अधिक संख्या में धागे नहीं हो सकते।

सेमाफोर उपयोग के मामले:

  1. डिस्क तक समवर्ती पहुंच को सीमित करना (यह प्रतिस्पर्धा डिस्क डिस्क के कारण प्रदर्शन को मार सकता है)
  2. धागा निर्माण सीमित
  3. JDBC कनेक्शन पूलिंग / सीमित
  4. नेटवर्क कनेक्शन थ्रॉटलिंग
  5. सीपीयू या स्मृति गहन कार्यों को थ्रॉटलिंग

सेमाफोर उपयोग के लिए इस लेख पर एक नज़र डालें ।

काउंटडाउनलॉच परिभाषा से javadocs:

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

यह कैसे काम करता है?

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

CountDownLatch मामलों का उपयोग करें:

  1. अधिकतम समानता प्राप्त करना: कभी-कभी हम अधिकतम समानता प्राप्त करने के लिए एक ही समय में कई सूत्र शुरू करना चाहते हैं
  2. निष्पादन शुरू करने से पहले एन धागे को पूरा करें
  3. गतिरोध का पता लगाने।

CountDownLatch अवधारणाओं को स्पष्ट रूप से समझने के लिए इस लेख पर एक नज़र डालें ।

इस लेख में फोर्क जॉइन पूल पर भी एक नज़र डालिए । यह काउंटडाउनचैच की कुछ समानताएं हैं ।


7

कहते हैं कि आप गोल्फ समर्थक दुकान पर चले गए, एक चौका लगाने की उम्मीद में,

जब आप समर्थक शॉप अटेंडेंट में से एक से टी टाइम प्राप्त करने के लिए कतार में खड़े होते हैं, तो अनिवार्य रूप से आपको कॉल किया जाता है proshopVendorSemaphore.acquire(), एक बार टी-टाइम मिलने के बाद, आपने कॉल किया। proshopVendorSemaphore.release()नोट: कोई भी फ्री अटेंडेंट आपकी सेवा, यानी साझा किए गए संसाधन की सेवा ले सकता है।

अब आप स्टार्टर के लिए चलते हैं, वह एक शुरू करता है CountDownLatch(4)और await()दूसरों की प्रतीक्षा करने के लिए कॉल करता है, आपके भाग के लिए जिसे आपने चेक-इन कहा जाता है CountDownLatchcountDown()और ऐसा ही बाकी के चार लोगों को भी होता है। जब सभी आते हैं, स्टार्टर आगे बढ़ता है ( await()कॉल रिटर्न)

अब, नौ छेदों के बाद जब आप में से प्रत्येक एक ब्रेक लेते हैं, तो काल्पनिक रूप से स्टार्टर को फिर से शामिल करने की अनुमति देता है, वह CountDownLatch(4)होल 10 से दूर करने के लिए एक 'नए' का उपयोग करता है , होल 1 के समान प्रतीक्षा / सिंक।

हालाँकि, यदि स्टार्टर ने इसके CyclicBarrierसाथ शुरुआत करने के लिए उपयोग किया है , तो वह एक दूसरे कुंडी के बजाय होल 10 में उसी उदाहरण को रीसेट कर सकता है, जो उपयोग और फेंकते हैं।


1
मुझे यकीन नहीं है कि मैं आपके उत्तर को समझ सकता हूं, लेकिन यदि आप यह वर्णन करने का प्रयास कर रहे हैं कि काउंटडाउनचैच और सेमाफोर कैसे काम करते हैं, तो यह सवाल का विषय नहीं है।
फाइनव्यू

10
दुर्भाग्य से मैं गोल्फ के बारे में कुछ नहीं जानता।
अंगूठी वाहक

लेकिन स्टार्टर स्टफ को केवल .acquire (खिलाड़ियों) के साथ किया जा सकता है और रिलीज के साथ रील्स की गई गिनती को बढ़ा सकता है। उलटी गिनती सिर्फ कार्यक्षमता और कोई पुन: प्रयोज्य नहीं है लगता है।
लस्सी किन्नुनेन

1

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


0

CountdownLatchथ्रेड्स await()विधि पर प्रतीक्षा करते हैं , जब तक कि गिनती शून्य तक नहीं पहुंच जाती। तो शायद आप चाहते हैं कि आपके सभी धागे किसी चीज के 3 आह्वान तक इंतजार करें, फिर सभी धागे जा सकते हैं। एक Latchआम तौर पर रीसेट नहीं किया जा सकता है।

एक Semaphoreधागे को परमिट प्राप्त करने की अनुमति देता है, जो बहुत सारे थ्रेड्स को एक ही बार में निष्पादित होने से रोकता है, अगर यह अनुमति नहीं दे सकता है तो अवरुद्ध हो सकता है। परमिट Semaphoreप्रतीक्षा की जा सकती है ताकि अन्य प्रतीक्षा धागे आगे बढ़ सकें ।

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