iPhone - ग्रैंड सेंट्रल डिस्पैच मुख्य धागा


145

मैं अपने ऐप्स में सफलता, भव्य केंद्रीय प्रेषण के साथ उपयोग कर रहा हूं, लेकिन मैं सोच रहा था कि इस तरह से कुछ का उपयोग करने का वास्तविक लाभ क्या है:

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

या और भी

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

मेरा मतलब है, दोनों ही मामलों में आप मुख्य थ्रेड पर निष्पादित होने के लिए ब्लॉक को निकाल रहे हैं, ठीक उसी जगह जहां ऐप चलता है और यह लोड को कम करने में मदद नहीं करेगा। पहले मामले में आपके पास कोई नियंत्रण नहीं है जब ब्लॉक चलेगा। मैंने देखा है कि ब्लाकों के मामलों को आग लगने के आधे घंटे बाद अंजाम दिया जाता है। दूसरा मामला, ऐसा ही है

[self doStuff];

सही?

मुझे आश्चर्य है कि आप लोग क्या सोचते हैं।


9
वैसे, एक मुख्य कतार को एक प्रेषण_sync में फेंकने के परिणामस्वरूप गतिरोध उत्पन्न होगा।
ब्रूक्स हान्स

5
बस डॉक्स में इसे पढ़ें: "dispatch_async के विपरीत, [dispatch_sync] तब तक वापस नहीं आता जब तक कि ब्लॉक समाप्त नहीं हो जाता। इस फ़ंक्शन को कॉल करना और मौजूदा कतार के परिणामों को लक्षित करना है।" ... लेकिन शायद मैं यह गलत पढ़ रहा हूं ... ( वर्तमान कतार का मतलब मुख्य धागा नहीं है)। अगर मैं गलत हूं तो कृपया सही करें।
ब्रूक्स हान्स

4
@ बरोकहंस हमेशा सच नहीं होते। यदि आप पहले से ही मुख्य धागे पर हैं तो यह गतिरोध उत्पन्न करेगा । यदि नहीं तो कोई गतिरोध नहीं होगा। यहाँ
हनी

जवाबों:


296

ब्लॉक को मुख्य कतार में भेजना आमतौर पर एक पृष्ठभूमि कतार से संकेत के लिए किया जाता है कि कुछ पृष्ठभूमि प्रसंस्करण जैसे समाप्त हो गया है

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

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

संभवत: अन्य उदाहरण हैं जहां आप मुख्य कतार में वापस भेजना चाहते हैं, लेकिन यह आम तौर पर इस तरह से किया जाता है अर्थात एक ब्लॉक से एक पृष्ठभूमि की कतार में भेज दिया गया।

  • पृष्ठभूमि प्रसंस्करण समाप्त -> अद्यतन यूआई
  • अगली कतार को शुरू करने के लिए पृष्ठभूमि कतार पर डेटा का हिस्सा -> संकेत मुख्य कतार
  • पृष्ठभूमि कतार पर आने वाले नेटवर्क डेटा -> संकेत मुख्य कतार जो संदेश आ गया है
  • आदि आदि

के रूप में क्यों आप मुख्य कतार से मुख्य कतार में भेजना चाहते हो सकता है ... ठीक है, आप आम तौर पर नहीं होगा, हालांकि अवधारणा संभव है कि आप रन लूप के आसपास अगली बार कुछ काम करने के लिए शेड्यूल कर सकते हैं।


ओह समझा। इसलिए, मैं सही हूं। ऐसा करने में कोई फायदा नहीं है कि अगर आप पहले से ही मुख्य कतार में हैं, अगर आप दूसरी कतार में हैं और यूआई को अपडेट करना चाहते हैं। धन्यवाद।
डक

बस इस बारे में बात करने के लिए मेरे जवाब को संपादित किया कि यह मुख्य कतार से ऐसा करने के लिए बहुत उपयोगी क्यों नहीं है।
रॉबिन समरहिल

इसके अलावा, मुझे लगता है कि आईओएस 4 में एक बग है (आईओएस 5 में चला गया हो सकता है), जहां मुख्य धागे से मुख्य कतार के लिए डिस्पैच_संकट बस एक लटका का कारण बनता है, इसलिए मैं पूरी तरह से ऐसा करने से बचता हूं।
जॉयरिक

10
यह बग नहीं है, यह अपेक्षित व्यवहार है। बहुत उपयोगी व्यवहार को स्वीकार नहीं किया गया है, लेकिन डिस्पैच_संकल्प का उपयोग करते समय आपको हमेशा डेडलॉक के बारे में पता होना चाहिए। आप सिस्टम को प्रोग्रामर त्रुटि से हर समय सुरक्षित रखने की उम्मीद नहीं कर सकते।
रॉबिन समरहिल

2
यहां बैकग्राउंड क्या है? मैं बैकग्राउंड
क्यू

16

ब्लॉक को मुख्य धागे से मुख्य कतार में भेजना उपयोगी हो सकता है। यह मुख्य कतार को अन्य ब्लॉकों को संभालने का मौका देता है जिन्हें कतारबद्ध किया गया है ताकि आप बाकी सभी चीजों को निष्पादित करने से रोक नहीं सकें।

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

यदि आपका कार्यक्रम कुछ नहीं करता है, लेकिन अपना पूरा जीवन घटनाओं पर प्रतिक्रिया देने में बिताता है तो यह काफी स्वाभाविक हो सकता है। आप बस अपने ईवेंट हैंडलर्स को मुख्य कतार पर चलाने के लिए सेट करते हैं और फिर डिस्पैच_मैन () कहते हैं, और आपको थ्रेड सुरक्षा के बारे में चिंता करने की आवश्यकता नहीं है।


11

उम्मीद है कि मैं आपके प्रश्न को सही ढंग से समझ रहा हूँ कि आप dispatch_async और dispatch_sync के बीच के अंतरों के बारे में सोच रहे हैं?

dispatch_async

ब्लॉक को असंगत रूप से एक कतार में भेज देगा। इसका अर्थ है कि यह ब्लॉक को कतार में भेज देगा और अपनी पद्धति में शेष कोड के निष्पादन पर जारी रखने से पहले उसके लौटने का इंतजार नहीं करेगा।

dispatch_sync

ब्लॉक को एक कतार में सिंक्रोनाइज़ किया जाएगा। यह विधि में शेष कोड के किसी भी अधिक निष्पादन को तब तक रोकेगा जब तक कि ब्लॉक निष्पादित करना समाप्त नहीं कर देता।

मैंने ज्यादातर dispatch_asyncमुख्य कतार से हटकर काम करने के लिए एक पृष्ठभूमि कतार का उपयोग किया है और डिवाइस में किसी भी अतिरिक्त कोर का लाभ उठा सकता हूं । फिर dispatch_asyncमुख्य थ्रेड के लिए अगर मुझे यूआई को अपडेट करने की आवश्यकता है।

सौभाग्य


1
धन्यवाद, लेकिन मैं मुख्य कतार में होने से कुछ को मुख्य कतार में भेजने से होने वाले फायदे के बारे में पूछ रहा हूं।
डक

9

एक जगह जहां यह उपयोगी है यूआई गतिविधियों के लिए, जैसे एक लंबा ऑपरेशन से पहले एक स्पिनर स्थापित करना:

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

काम नहीं करेगा, क्योंकि आप अपनी लंबी चीज़ के दौरान मुख्य धागे को अवरुद्ध कर रहे हैं और UIKit को वास्तव में स्पिनर शुरू नहीं करने दे रहे हैं।

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

रन लूप पर नियंत्रण लौटाएगा, जो यूआई अपडेट को शेड्यूल करेगा, स्पिनर को शुरू करेगा, फिर अगली चीज़ को डिस्पैच कतार से हटा देगा, जो कि आपका वास्तविक प्रसंस्करण है। जब आपका प्रसंस्करण किया जाता है, तो एनीमेशन स्टॉप कहा जाता है, और आप रन लूप में लौटते हैं, जहां यूआई फिर स्टॉप के साथ अपडेट हो जाता है।


@Jerceratops हाँ, लेकिन यह वर्तमान रनअप को पूरा करने की अनुमति देता है।
डैन रोसेनस्टार्क 16

3
हाँ, लेकिन यह अभी भी भयानक है। यह अभी भी UI ब्लॉक करता है। मैं इसके ठीक बाद एक और बटन दबा सकता हूं। या कोशिश करें और स्क्रॉल करें। "(कुछ लंबा करें)" मुख्य धागे पर नहीं होना चाहिए, और बटन को "फिनिश" पर क्लिक करने के लिए डिस्पैच_सिंक स्वीकार्य समाधान नहीं है।
जेरकरटॉप्स


1

Async का अर्थ है अतुल्यकालिक और आपको उस समय का अधिकांश उपयोग करना चाहिए। आपको मुख्य थ्रेड पर सिंक को कभी भी कॉल नहीं करना चाहिए क्योंकि यह कार्य पूरा होने तक आपके UI को लॉक कर देगा। आप यहाँ स्विफ्ट में ऐसा करने का एक बेहतर तरीका है:

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

मेरे रेपो में इसका मानक कार्य शामिल है, इसे देखें : https://github.com/goktugyil/EZSwiftExtensions

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