सीरियल कतार पर dispatch_async और dispatch_sync के बीच अंतर?


125

मैंने इस तरह एक सीरियल कतार बनाई है:

    dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL);

dispatch_asyncइस तरह कहा जाता है के बीच क्या अंतर है

 dispatch_async(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_async(_serialQueue, ^{ /* TASK 2 */ });

और dispatch_syncइस तरह इस सीरियल कतार पर बुलाया?

 dispatch_sync(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_sync(_serialQueue, ^{ /* TASK 2 */ });

मेरी समझ यह है कि परवाह किए बिना किस प्रेषण विधि का उपयोग किया जाता है, TASK 1निष्पादित किया जाएगा और पहले पूरा किया जाएगा TASK 2, सही?

जवाबों:


409

हाँ। सीरियल कतार का उपयोग कार्यों के सीरियल निष्पादन को सुनिश्चित करता है। अंतर केवल इतना है कि dispatch_syncब्लॉक समाप्त होने के बाद केवल वापसी करते समयdispatch_async कतार में शामिल होने के बाद वापस आते हैं और समाप्त नहीं हो सकते।

इस कोड के लिए

dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");

यह प्रिंट कर सकते हैं 2413या 2143या 1234लेकिन 1हमेशा से पहले3

इस कोड के लिए

dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");

यह हमेशा प्रिंट होता है 1234


नोट: पहले कोड के लिए, यह प्रिंट नहीं होगा 1324। क्योंकि निष्पादित होने के बादprintf("3") भेजा जाता है। और किसी कार्य को भेजे जाने के बाद ही निष्पादित किया जा सकता है। printf("2")


कार्यों का निष्पादन समय कुछ भी नहीं बदलता है। यह कोड हमेशा प्रिंट होता है12

dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); });
dispatch_async(_serialQueue, ^{ printf("2"); });

क्या हो सकता है

  • थ्रेड 1: सीरियल कतार में एक समय लेने वाला कार्य (कार्य 1) ​​डिस्पैच_संकट
  • थ्रेड 2: कार्य 1 निष्पादित करना शुरू करें
  • थ्रेड 1: सीरियल कतार के लिए एक और कार्य (कार्य 2) प्रेषित करें
  • थ्रेड 2: कार्य 1 समाप्त। कार्य 2 को निष्पादित करना शुरू करें
  • थ्रेड 2: कार्य 2 समाप्त।

और आप हमेशा देखते हैं 12


7
यह 2134 और 1243
मैटो गोबी

मेरा सवाल यह है कि हमने सामान्य तरीके से ऐसा क्यों नहीं किया? printf("1");printf("2") ;printf("3") ;printf("4")- की तुलना मेंdispatch_sync
androniennn

दूसरे उदाहरण के लिए @androniennn? क्योंकि कुछ अन्य धागे dispatch_sync(_serialQueue, ^{ /*change shared data*/ });एक ही समय में चल सकते हैं।
ब्रायन चेन

1
@ asma22 कई थ्रेड / प्रेषण कतारों के बीच एक गैर-थ्रेड सुरक्षित ऑब्जेक्ट साझा करना बहुत उपयोगी है। यदि आप केवल सीरियल कतार में ऑब्जेक्ट को एक्सेस करते हैं, तो आप जानते हैं कि आप इसे सुरक्षित रूप से एक्सेस कर रहे हैं।
ब्रायन चेन

1
मेरा मतलब धारावाहिक निष्पादन से है । इस दृष्टि से कि सभी कार्यों को एक ही कतार में अन्य कार्यों के संबंध में क्रमबद्ध निष्पादित किया जाता है। क्योंकि यह अभी भी अन्य कतारों के समवर्ती हो सकता है। यह जीसीडी का पूरा बिंदु है कि कार्यों को भेजा जा सकता है और समवर्ती रूप से निष्पादित किया जा सकता है।
ब्रायन चेन

19

के बीच अंतर dispatch_syncऔर dispatch_asyncसरल है।

अपने दोनों उदाहरणों में, TASK 1हमेशा पहले निष्पादित करेंगे TASK 2क्योंकि इसे इससे पहले भेजा गया था।

dispatch_syncहालाँकि, उदाहरण के लिए, आप प्रेषण और निष्पादितTASK 2 होने के बाद तक प्रेषण नहीं करेंगे । इसे "ब्लॉकिंग" कहा जाता है । जब तक कार्य निष्पादित नहीं होता तब तक आपका कोड प्रतीक्षा करता है (या "ब्लॉक")।TASK 1

में dispatch_asyncउदाहरण के लिए, अपने कोड पूरा करने के लिए निष्पादन के लिए इंतजार नहीं होंगे। दोनों ब्लॉक कतार में भेजेंगे (और संलग्न किए जाएंगे) और आपके बाकी कोड उस थ्रेड पर निष्पादित होते रहेंगे। फिर भविष्य में किसी बिंदु पर, (आपकी कतार के लिए और क्या भेजा गया है पर निर्भर करता है), Task 1निष्पादित करेगा और फिर Task 2निष्पादित करेगा।


2
मुझे लगता है कि आपके गलत आदेश मिले। पहला उदाहरण asyncगैर-अवरोधक संस्करण है
ब्रायन चेन

मैंने आपके उत्तर को संपादित किया है जो मुझे लगता है कि आपका मतलब है । यदि यह मामला नहीं है, तो कृपया इसे बदलें और स्पष्ट करें।
डेवलपर

1
क्या होगा यदि आप एक ही कतार पर dispatch_sync और फिर dispatch_async कहते हैं? (और इसके विपरीत)
0xSina

1
एक सीरियल कतार पर, दोनों कार्यों को अभी भी एक के बाद एक निष्पादित किया जाता है। पहले मामले में, कॉलर पहले ब्लॉक के समाप्त होने का इंतजार करता है लेकिन दूसरे ब्लॉक का इंतजार नहीं करता है। दूसरे मामले में, कॉलर पहले ब्लॉक के समाप्त होने का इंतजार नहीं करता है, लेकिन दूसरे ब्लॉक का इंतजार करता है। लेकिन चूंकि कतार क्रम में ब्लॉकों को निष्पादित करती है, इसलिए कॉलर प्रभावी रूप से दोनों के समाप्त होने की प्रतीक्षा करता है।
gnasher729

1
एक ब्लॉक अपनी स्वयं की कतार पर एक प्रेषण_संकल्प भी कर सकता है (आगे के ब्लॉक जो बाद में निष्पादित किए जाएंगे); स्वयं धारावाहिक कतार या मुख्य कतार पर पहुंच से बाहर हो जाएगा। इस स्थिति में, कॉलर मूल ब्लॉक के समाप्त होने की प्रतीक्षा करेगा, लेकिन अन्य ब्लॉकों के लिए नहीं। बस याद रखें: dispatch_sync कतार के अंत में ब्लॉक डालता है, कतार कोड को तब तक निष्पादित करती है जब तक कि ब्लॉक समाप्त नहीं हो जाता है, और फिर डिस्पैच_sync वापस आ जाता है। dispatch_async बस कतार के अंत में ब्लॉक जोड़ता है।
gnasher729

5

यह सभी मुख्य कतार से संबंधित है। 4 क्रमोन्नति हैं।

i) सीरियल कतार, प्रेषण async: यहाँ कार्य एक के बाद एक निष्पादित होंगे, लेकिन मुख्य थ्रेड (UI पर प्रभाव) वापसी की प्रतीक्षा नहीं करेंगे

ii) सीरियल कतार, प्रेषण सिंक: यहां कार्य एक के बाद एक निष्पादित होंगे, लेकिन मुख्य थ्रेड (UI पर प्रभाव) पिछड़ापन दिखाएगा

iii) समवर्ती कतार, async प्रेषण: यहां कार्य समानांतर में निष्पादित होंगे और मुख्य थ्रेड (UI पर प्रभाव) वापसी की प्रतीक्षा नहीं करेगा और चिकना होगा।

iv) समवर्ती कतार, प्रेषण सिंक: यहां कार्य समानांतर में निष्पादित होंगे, लेकिन मुख्य थ्रेड (UI पर प्रभाव) बड़ा असर दिखाएगा

समवर्ती या सीरियल कतार की आपकी पसंद इस बात पर निर्भर करती है कि आपको अगले कार्य के लिए पिछले कार्य से आउटपुट की आवश्यकता है या नहीं। यदि आप पिछले कार्य पर निर्भर हैं, तो धारावाहिक कतार को अपनाएं अन्यथा समवर्ती कतार लें।

और अंत में यह मुख्य धागे में वापस घुसने का एक तरीका है जब हम अपने व्यवसाय के साथ होते हैं:

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