एक और ब्लॉक शुरू करने से पहले दो async ब्लॉक निष्पादित होने तक प्रतीक्षा की जा रही है


192

GCD का उपयोग करते समय, हम तब तक इंतजार करना चाहते हैं जब तक कि दो async ब्लॉक निष्पादित नहीं हो जाते हैं और निष्पादन के अगले चरणों पर जाने से पहले किया जाता है। उसे करने का सबसे अच्छा तरीका कौन सा है?

हमने निम्नलिखित की कोशिश की, लेकिन यह काम नहीं करता है:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block1
});


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block2
});

// wait until both the block1 and block2 are done before start block3
// how to do that?

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block3
});

स्विफ्ट 5 के लिए मेरा जवाब देखें जो आपकी समस्या को हल करने के लिए छह अलग-अलग तरीके पेश करता है।
इमानो पेटिट

जवाबों:


301

उपयोग प्रेषण समूहों: देखने के लिए यहाँ एप्पल के आईओएस डेवलपर लाइब्रेरी की कन्करेंसी प्रोग्रामिंग गाइड के "डिस्पैच कतार" अध्याय में एक उदाहरण के लिए, "प्रतीक्षा कर रहा है पर कतारबद्ध कार्य के समूह"

आपका उदाहरण कुछ इस तरह दिख सकता है:

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block1
    NSLog(@"Block1");
    [NSThread sleepForTimeInterval:5.0];
    NSLog(@"Block1 End");
});


dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block2
    NSLog(@"Block2");
    [NSThread sleepForTimeInterval:8.0];
    NSLog(@"Block2 End");
});

dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block3
    NSLog(@"Block3");
});

// only for non-ARC projects, handled automatically in ARC-enabled projects.
dispatch_release(group);

और इस तरह उत्पादन का उत्पादन कर सकता है:

2012-08-11 16:10:18.049 Dispatch[11858:1e03] Block1
2012-08-11 16:10:18.052 Dispatch[11858:1d03] Block2
2012-08-11 16:10:23.051 Dispatch[11858:1e03] Block1 End
2012-08-11 16:10:26.053 Dispatch[11858:1d03] Block2 End
2012-08-11 16:10:26.054 Dispatch[11858:1d03] Block3

3
ठंडा। क्या एक बार समूह से जुड़े async कार्य / ब्लॉक, क्रमिक रूप से या समवर्ती रूप से निष्पादित किए जाएंगे? मेरा मतलब है, मान लें कि ब्लॉक 1 और ब्लॉक 2 अब एक समूह के साथ जुड़े हुए हैं, क्या ब्लॉक 2 तब तक इंतजार करेगा जब तक कि ब्लॉक 1 को निष्पादित करने से पहले किया जाता है?
टॉम

9
यह आप पर निर्भर है। एक समूह पैरामीटर जोड़ा के साथ की dispatch_group_asyncतरह है dispatch_async। इसलिए यदि आप ब्लॉक 1 और ब्लॉक 2 के लिए अलग-अलग कतारों का उपयोग करते हैं या उन्हें एक ही समवर्ती कतार पर शेड्यूल करते हैं, तो वे समवर्ती चला सकते हैं; यदि आप उन्हें एक ही सीरियल कतार पर शेड्यूल करते हैं, तो वे क्रमिक रूप से चलेंगे। यह समूहों के बिना ब्लॉक को शेड्यूल करने से अलग नहीं है।
जर्न इरिच

1
क्या यह वेब सेवा पोस्ट निष्पादित करने के लिए भी लागू होता है?
SleepNot

क्या आप ध्यान देते हैं कि आपके ब्लॉक में सोने के समय के बराबर समय नहीं है? ऐसा क्यों होगा?
डेमन युआन 12

2
एआरसी में बस डिस्पैच_रेल (समूह) को हटा दें;
लोरेटोपरिसी

272

Jörn Eyrich उत्तर पर विस्तार करना (यदि आप इस एक को बढ़ाते हैं तो उसका उत्तर दें), यदि आपके पास dispatch_asyncअपने ब्लॉक के लिए कॉल पर नियंत्रण नहीं है , जैसा कि async पूरा होने वाले ब्लॉक के लिए मामला हो सकता है, तो आप GCD समूहों का उपयोग करके dispatch_group_enterऔर dispatch_group_leaveसीधे उपयोग कर सकते हैं ।

इस उदाहरण में, हम दिखावा कर रहे हैं computeInBackgroundकि हम कुछ बदल नहीं सकते हैं (कल्पना करें कि यह एक प्रतिनिधि कॉलबैक है, NSURLConnection पूर्णहैंडलर, या जो भी हो), और इस प्रकार हमारे पास प्रेषण कॉल तक पहुंच नहीं है।

// create a group
dispatch_group_t group = dispatch_group_create();

// pair a dispatch_group_enter for each dispatch_group_leave
dispatch_group_enter(group);     // pair 1 enter
[self computeInBackground:1 completion:^{
    NSLog(@"1 done");
    dispatch_group_leave(group); // pair 1 leave
}];

// again... (and again...)
dispatch_group_enter(group);     // pair 2 enter
[self computeInBackground:2 completion:^{
    NSLog(@"2 done");
    dispatch_group_leave(group); // pair 2 leave
}];

// Next, setup the code to execute after all the paired enter/leave calls.
//
// Option 1: Get a notification on a block that will be scheduled on the specified queue:
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"finally!");
});

// Option 2: Block an wait for the calls to complete in code already running
// (as cbartel points out, be careful with running this on the main/UI queue!):
//
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // blocks current thread
// NSLog(@"finally!");

इस उदाहरण में, computeInBackground: पूर्णता: के रूप में कार्यान्वित किया गया है:

- (void)computeInBackground:(int)no completion:(void (^)(void))block {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"%d starting", no);
        sleep(no*2);
        block();
    });
}

आउटपुट (एक रन से टाइमस्टैम्प के साथ):

12:57:02.574  2 starting
12:57:02.574  1 starting
12:57:04.590  1 done
12:57:06.590  2 done
12:57:06.591  finally!

1
@ oneuroburɳ उपरोक्त कोड मुख्य धागे पर प्रतीक्षा करता है। मेरा मानना ​​है कि यह मुख्य थ्रेड को ब्लॉक करेगा और यूआई को गैर-जिम्मेदार होने का कारण देगा जब तक कि पूरा समूह पूरा न हो जाए। मैं प्रतीक्षा को पृष्ठभूमि थ्रेड में ले जाने की सलाह देता हूं। उदाहरण के लिए, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0)
cbartel

2
@cbartel, अच्छी पकड़! मैंने आपकी टिप्पणी को दर्शाने के लिए उदाहरण कोड अपडेट किया है। कई बार आपको मुख्य कतार पर कॉलबैक की आवश्यकता होती है - उस स्थिति में हालांकि dispatch_queue_notifyबेहतर होने की संभावना है (जब तक कि अवरुद्ध समय कम होने की गारंटी न हो)।
euroburɳ

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

यदि आप ARC का उपयोग कर रहे हैं, तो आपको dispatch_release पर कॉल करने की आवश्यकता नहीं है: stackoverflow.com/questions/8618632/…
robeuroburɳ

3
अच्छी पोस्ट जो आगे बताते हैं कि: commandshift.co.uk/blog/2014/03/19/...
Rizon

97

स्विफ्ट 5.1 के साथ, ग्रैंड सेंट्रल डिस्पैच आपकी समस्या को हल करने के कई तरीके प्रदान करता है। अपनी आवश्यकताओं के अनुसार, आप निम्नलिखित खेल के मैदान के स्निपेट्स में दिखाए गए सात पैटर्न में से एक चुन सकते हैं ।


# 1। का उपयोग कर DispatchGroup, DispatchGroup'एस notify(qos:flags:queue:execute:)और DispatchQueue' एसasync(group:qos:flags:execute:)

Apple डेवलपर कॉन्सिक्वैरिटी प्रोग्रामिंग गाइड के बारे में बताता हैDispatchGroup :

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

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()

queue.async(group: group) {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
}

queue.async(group: group) {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
}

group.notify(queue: queue) {
    print("#3 finished")
}

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 */

# 2। का उपयोग करते हुए DispatchGroup, DispatchGroup's wait(), DispatchGroup' s enter()और DispatchGroup'sleave()

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()

group.enter()
queue.async {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
    group.leave()
}

group.enter()
queue.async {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
    group.leave()
}

queue.async {
    group.wait()
    print("#3 finished")
}

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 */

ध्यान दें कि आप भी मिश्रण कर सकते हैं DispatchGroup wait()के साथ DispatchQueue async(group:qos:flags:execute:)या मिश्रण DispatchGroup enter()और DispatchGroup leave()साथ DispatchGroup notify(qos:flags:queue:execute:)


# 3। का उपयोग करते हुए और कीDispatch​Work​Item​Flags barrierDispatchQueueasync(group:qos:flags:execute:)

स्विफ्ट 4 के लिए ग्रैंड सेंट्रल डिस्पैच ट्यूटोरियल: रेवेंडरलिच डॉट कॉम का भाग 1/2 लेख बाधाओं के लिए एक परिभाषा देता है :

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

उपयोग:

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)

queue.async {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
}

queue.async {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
}

queue.async(flags: .barrier) {
    print("#3 finished")
}

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 */

# 4। का उपयोग कर DispatchWorkItem, Dispatch​Work​Item​Flags'एस barrierऔर DispatchQueue' एसasync(execute:)

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)

queue.async {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
}

queue.async {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
}

let dispatchWorkItem = DispatchWorkItem(qos: .default, flags: .barrier) {
    print("#3 finished")
}

queue.async(execute: dispatchWorkItem)

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 */

# 5। का उपयोग कर DispatchSemaphore, DispatchSemaphore'एस wait()और DispatchSemaphore' एसsignal()

सोरूस खान्लू ने जीसीडी हैंडबुक ब्लॉग पोस्ट में निम्नलिखित पंक्तियां लिखी हैं :

एक सेमाफोर का उपयोग करके, हम एक थ्रेड को समय की एक मनमानी राशि के लिए ब्लॉक कर सकते हैं, जब तक कि किसी अन्य धागे से संकेत नहीं भेजा जाता है। बाकी GCD की तरह सेमाफोर थ्रेड-सेफ हैं, और इन्हें कहीं से भी ट्रिगर किया जा सकता है। जब एक एसिंक्रोनस एपीआई है जिसे आपको सिंक्रोनस बनाने की आवश्यकता होती है, तो सेमाफोरस का उपयोग किया जा सकता है, लेकिन आप इसे संशोधित नहीं कर सकते।

Apple डेवलपर API संदर्भ DispatchSemaphore init(value:​)इनिशियलाइज़र के लिए निम्नलिखित चर्चा भी देता है:

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

उपयोग:

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let semaphore = DispatchSemaphore(value: 0)

queue.async {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
    semaphore.signal()
}

queue.async {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
    semaphore.signal()
}

queue.async {
    semaphore.wait()
    semaphore.wait()    
    print("#3 finished")
}

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 */

# 6। का उपयोग करते हुए OperationQueueऔर OperationकीaddDependency(_:)

Apple डेवलपर API संदर्भ के बारे में बताता है Operation​Queue:

ऑपरेशन कतारें libdispatchअपने संचालन के निष्पादन को आरंभ करने के लिए पुस्तकालय (ग्रैंड सेंट्रल डिस्पैच के रूप में भी जानी जाती हैं) का उपयोग करती हैं।

उपयोग:

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let operationQueue = OperationQueue()

let blockOne = BlockOperation {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
}

let blockTwo = BlockOperation {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
}

let blockThree = BlockOperation {
    print("#3 finished")
}

blockThree.addDependency(blockOne)
blockThree.addDependency(blockTwo)

operationQueue.addOperations([blockThree, blockTwo, blockOne], waitUntilFinished: false)

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 or
 #2 started
 #1 started
 #2 finished
 #1 finished
 #3 finished
 */

# 7। का उपयोग करते हुए OperationQueueऔर OperationQueueके addBarrierBlock(_:)(आईओएस 13 की आवश्यकता है)

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let operationQueue = OperationQueue()

let blockOne = BlockOperation {
    print("#1 started")
    Thread.sleep(forTimeInterval: 5)
    print("#1 finished")
}

let blockTwo = BlockOperation {
    print("#2 started")
    Thread.sleep(forTimeInterval: 2)
    print("#2 finished")
}

operationQueue.addOperations([blockTwo, blockOne], waitUntilFinished: false)
operationQueue.addBarrierBlock {
    print("#3 finished")
}

/*
 prints:
 #1 started
 #2 started
 #2 finished
 #1 finished
 #3 finished
 or
 #2 started
 #1 started
 #2 finished
 #1 finished
 #3 finished
 */

क्या प्रत्येक समूह के लिए (और बिना अर्ध-संस्करणों के) group.enter () और group.leave () का उपयोग किए बिना async कॉल का कोई समाधान है? जैसे अगर मुझे किसी सर्वर के लिए एक async अनुरोध की प्रतीक्षा करने की आवश्यकता है, तो उसके बाद दूसरे async अनुरोध और इतने पर प्रतीक्षा करें। मैंने यह लेख avanderlee.com/swift/asynchronous-operations पढ़ा है, लेकिन मुझे इसका साधारण उपयोग ब्लॉकऑपरेशन से तुलना करते हुए नहीं दिखता है
Woof

58

एक अन्य जीसीडी विकल्प एक बाधा है:

dispatch_queue_t queue = dispatch_queue_create("com.company.app.queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{ 
    NSLog(@"start one!\n");  
    sleep(4);  
    NSLog(@"end one!\n");
});

dispatch_async(queue, ^{  
    NSLog(@"start two!\n");  
    sleep(2);  
    NSLog(@"end two!\n"); 
});

dispatch_barrier_async(queue, ^{  
    NSLog(@"Hi, I'm the final block!\n");  
});

बस एक समवर्ती कतार बनाएं, अपने दो ब्लॉकों को भेजें, और फिर अंतिम ब्लॉक को अवरोध के साथ भेजें, जिससे यह अन्य दो के खत्म होने का इंतजार करेगा।


क्या कोई समस्या है अगर मैंने नींद का उपयोग नहीं किया (4);
हिमंत

नहीं, निश्चित रूप से, इसके साथ कोई समस्या नहीं है। वास्तव में, आप व्यावहारिक रूप से कभी नहीं चाहते हैं sleep()! मैंने केवल उन sleep()कॉलों को शैक्षणिक कारणों से जोड़ा है, जिससे ब्लॉक लंबे समय तक चलते हैं ताकि आप देख सकें कि वे समवर्ती रूप से चलते हैं। इस तुच्छ उदाहरण में, इन की अनुपस्थिति में sleep(), ये दोनों ब्लॉक इतनी तेज़ी से चल सकते हैं कि प्रेषण ब्लॉक शुरू हो सकता है और खत्म हो सकता है इससे पहले कि आप समवर्ती निष्पादन का अनुभव कर सकें। लेकिन sleep()अपने कोड में नहीं है।
रोब

39

मुझे पता है कि आपने जीसीडी के बारे में पूछा था, लेकिन अगर आप चाहते हैं, तो NSOperationQueueइस तरह के सामान को वास्तव में सुंदर रूप से संभालते हैं, जैसे:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"Starting 3");
}];

NSOperation *operation;

operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"Starting 1");
    sleep(7);
    NSLog(@"Finishing 1");
}];

[completionOperation addDependency:operation];
[queue addOperation:operation];

operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"Starting 2");
    sleep(5);
    NSLog(@"Finishing 2");
}];

[completionOperation addDependency:operation];
[queue addOperation:operation];

[queue addOperation:completionOperation];

3
यह तब ठीक होता है जब आपके NSBlockOperation के अंदर का कोड सिंक्रोनस होता है। लेकिन क्या होगा अगर यह नहीं है, और आप अपने async ऑपरेशन के पूरा होने पर ट्रिगर करना चाहते हैं?
ग्रेग मैलिक

3
@GregMaletic उस मामले में, मैं एक NSOperationउपवर्ग बनाता हूं जो समवर्ती होता है और isFinishedजब अतुल्यकालिक प्रक्रिया पूरी हो जाती है तो सेट हो जाता है। तब निर्भरताएँ ठीक काम करती हैं।
रोब

@GregMaletic उदाहरणों के लिए stackoverflow.com/questions/18429011/… और stackoverflow.com/questions/17426855/… देखें ।
रोब

1
@GregMaletic हाँ, आप इसका उपयोग कर सकते हैं, भी (जब तक dispatch_semaphore_waitकि मुख्य कतार पर जगह नहीं ले रहा है और जब तक आपके संकेत और प्रतीक्षा संतुलित हैं)। जब तक आपकी मुख्य कतार को ब्लॉक नहीं करते हैं, तब तक एक सेमाफोर दृष्टिकोण ठीक है, अगर आपको संचालन के लचीलेपन की आवश्यकता नहीं है (उदाहरण के लिए उन्हें रद्द करने की क्षमता, कंसीडर की डिग्री को नियंत्रित करने की क्षमता आदि)।
रोब

1
@ Reza.Ab - यदि आपको कार्य दो शुरू करने से पहले कार्य समाप्त करने की आवश्यकता है, तो उन कार्यों के बीच एक निर्भरता जोड़ें। या यदि कतार हमेशा एक बार में केवल एक ही कार्य प्रदर्शन कर रहा है, यह एक धारावाहिक कतार स्थापना करके बनाने maxConcurrentOperationCountके लिए 1। आप भी आपरेशन के प्राथमिकता निर्धारित कर सकते हैं, दोनों qualityOfServiceऔर queuePriorityहै, लेकिन इन निर्भरता और / या कतार संगामिति की डिग्री की तुलना में कार्य प्राथमिकता के आधार पर एक कहीं अधिक सूक्ष्म प्रभाव पड़ता है।
रोब

4

ऊपर दिए गए उत्तर सभी शांत हैं, लेकिन वे सभी एक चीज से चूक गए। समूह थ्रेड में कार्य (ब्लॉक) निष्पादित करता है, जहां आपने उपयोग किया था dispatch_group_enter/ dispatch_group_leave

- (IBAction)buttonAction:(id)sender {
      dispatch_queue_t demoQueue = dispatch_queue_create("com.demo.group", DISPATCH_QUEUE_CONCURRENT);
      dispatch_async(demoQueue, ^{
        dispatch_group_t demoGroup = dispatch_group_create();
        for(int i = 0; i < 10; i++) {
          dispatch_group_enter(demoGroup);
          [self testMethod:i
                     block:^{
                       dispatch_group_leave(demoGroup);
                     }];
        }

        dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
          NSLog(@"All group tasks are done!");
        });
      });
    }

    - (void)testMethod:(NSInteger)index block:(void(^)(void))completeBlock {
      NSLog(@"Group task started...%ld", index);
      NSLog(@"Current thread is %@ thread", [NSThread isMainThread] ? @"main" : @"not main");
      [NSThread sleepForTimeInterval:1.f];

      if(completeBlock) {
        completeBlock();
      }
    }

यह बनाई गई समवर्ती कतार में चलता है demoQueue। अगर मैं कोई कतार नहीं बनाता, तो यह मुख्य धागे में चलता है ।

- (IBAction)buttonAction:(id)sender {
    dispatch_group_t demoGroup = dispatch_group_create();
    for(int i = 0; i < 10; i++) {
      dispatch_group_enter(demoGroup);
      [self testMethod:i
                 block:^{
                   dispatch_group_leave(demoGroup);
                 }];
    }

    dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
      NSLog(@"All group tasks are done!");
    });
    }

    - (void)testMethod:(NSInteger)index block:(void(^)(void))completeBlock {
      NSLog(@"Group task started...%ld", index);
      NSLog(@"Current thread is %@ thread", [NSThread isMainThread] ? @"main" : @"not main");
      [NSThread sleepForTimeInterval:1.f];

      if(completeBlock) {
        completeBlock();
      }
    }

और दूसरे थ्रेड में निष्पादित कार्यों को बनाने का तीसरा तरीका है:

- (IBAction)buttonAction:(id)sender {
      dispatch_queue_t demoQueue = dispatch_queue_create("com.demo.group", DISPATCH_QUEUE_CONCURRENT);
      //  dispatch_async(demoQueue, ^{
      __weak ViewController* weakSelf = self;
      dispatch_group_t demoGroup = dispatch_group_create();
      for(int i = 0; i < 10; i++) {
        dispatch_group_enter(demoGroup);
        dispatch_async(demoQueue, ^{
          [weakSelf testMethod:i
                         block:^{
                           dispatch_group_leave(demoGroup);
                         }];
        });
      }

      dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
        NSLog(@"All group tasks are done!");
      });
      //  });
    }

बेशक, जैसा कि उल्लेख किया dispatch_group_asyncगया है कि आप जो चाहें प्राप्त करने के लिए उपयोग कर सकते हैं।


3

पहला उत्तर अनिवार्य रूप से सही है, लेकिन यदि आप वांछित परिणाम प्राप्त करने के लिए सबसे सरल तरीका चाहते हैं, तो यहां एक स्टैंड-अलोन कोड उदाहरण है जो यह दर्शाता है कि यह कैसे एक सेमाफोर के साथ किया जाता है (जो कि कैसे प्रेषण समूह पर्दे के पीछे काम करता है, जेएफआई) :

#include <dispatch/dispatch.h>
#include <stdio.h>

main()
{
        dispatch_queue_t myQ = dispatch_queue_create("my.conQ", DISPATCH_QUEUE_CONCURRENT);
        dispatch_semaphore_t mySem = dispatch_semaphore_create(0);

        dispatch_async(myQ, ^{ printf("Hi I'm block one!\n"); sleep(2); dispatch_semaphore_signal(mySem);});
        dispatch_async(myQ, ^{ printf("Hi I'm block two!\n"); sleep(4); dispatch_semaphore_signal(mySem);});
        dispatch_async(myQ, ^{ dispatch_semaphore_wait(mySem, DISPATCH_TIME_FOREVER); printf("Hi, I'm the final block!\n"); });
        dispatch_main();
}

7
दो अवलोकन: 1. आप एक याद कर रहे हैं dispatch_semaphore_wait। आपके पास दो सिग्नल हैं, इसलिए आपको दो वेट चाहिए। जैसे ही, आपका "पूर्ण" ब्लॉक शुरू होगा जैसे ही पहला ब्लॉक सेमीफोर को इंगित करता है, लेकिन अन्य ब्लॉक खत्म होने से पहले; 2. यह एक iOS सवाल था, मैं इसके इस्तेमाल को हतोत्साहित करता हूँ dispatch_main
रोब

1
मैं रोब से सहमत हूं। यह एक वैध समाधान नहीं है। dispatch_semaphore_waitजैसे ही दोनों में से किसी के रूप में अवरोधित कर देगा dispatch_semaphore_signalतरीकों कहा जाता है। यह काम करने के लिए प्रकट हो सकता है कारण यह है कि printfब्लॉक 'एक' और 'दो' के printfलिए तुरंत होते हैं, और 'अंत' के लिए प्रतीक्षा के बाद होता है - इस प्रकार ब्लॉक एक के बाद 2 सेकंड के लिए सो गया है। यदि आप sleepकॉल के बाद प्रिंटफ़ डालते हैं, तो आपको 'एक' के लिए आउटपुट मिलेगा, फिर 2 सेकंड बाद में 'अंत' के लिए, फिर 2 सेकंड बाद 'दो' के लिए।
17:euroburɳ

1

स्विफ्ट में स्वीकृत उत्तर:

let group = DispatchGroup()

group.async(group: DispatchQueue.global(qos: .default), execute: {
    // block1
    print("Block1")
    Thread.sleep(forTimeInterval: 5.0)
    print("Block1 End")
})


group.async(group: DispatchQueue.global(qos: .default), execute: {
    // block2
    print("Block2")
    Thread.sleep(forTimeInterval: 8.0)
    print("Block2 End")
})

dispatch_group_notify(group, DispatchQueue.global(qos: .default), {
    // block3
    print("Block3")
})

// only for non-ARC projects, handled automatically in ARC-enabled projects.
dispatch_release(group)

0

स्विफ्ट 4.2 का उदाहरण:

let group = DispatchGroup.group(count: 2)
group.notify(queue: DispatchQueue.main) {
     self.renderingLine = false
     // all groups are done
}
DispatchQueue.main.async {
    self.renderTargetNode(floorPosition: targetPosition, animated: closedContour) {
        group.leave()
        // first done
    }
    self.renderCenterLine(position: targetPosition, animated: closedContour) {
        group.leave()
        // second done
    }
 }

group.leave()कारण दुर्घटना
बेन

-3

कहने के लिए नहीं कि अन्य उत्तर कुछ परिस्थितियों के लिए महान नहीं हैं, लेकिन यह एक स्निपेट है जो मैं हमेशा Google से उपयोगकर्ता करता हूं:

- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {


    if (signInDoneSel) {
        [self performSelector:signInDoneSel];
    }

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