অন্য ব্লক শুরু করার আগে দুটি অ্যাসিঙ্ক ব্লক কার্যকর না হওয়া পর্যন্ত অপেক্ষা করা


192

জিসিডি ব্যবহার করার সময় আমরা দুটি অপ্রয়োজনীয় ব্লক কার্যকর না হওয়া এবং মৃত্যুদন্ডের পরবর্তী ধাপগুলিতে এগিয়ে যাওয়ার আগে অপেক্ষা করতে চাই। এটি করার সর্বোত্তম উপায় কী?

আমরা নিম্নলিখিতগুলি চেষ্টা করেছিলাম, তবে এটি কার্যকর হবে বলে মনে হচ্ছে না:

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

প্রেরণকারী গোষ্ঠীগুলি ব্যবহার করুন: এখানে একটি উদাহরণের জন্য দেখুন , অ্যাপলের আইওএস বিকাশকারী লাইব্রেরির কনকুরেন্সি প্রোগ্রামিং গাইডের "ডিসপ্যাচ ক্যুয়েস" অধ্যায়টিতে "কুইউড টাস্কগুলির গোষ্ঠীগুলির অপেক্ষায় থাকা" see

আপনার উদাহরণটি এর মতো দেখতে পারে:

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 এখন একটি গোষ্ঠীর সাথে সম্পর্কিত, ব্লক 1 এটি কার্যকর করা শুরু করার আগে ব্লক 1 না হওয়া পর্যন্ত অপেক্ষা করবে?
টম

9
এটা তোমার উপর. dispatch_group_asyncশুধু ভালো হয় dispatch_asyncএকদল প্যারামিটার যোগ করে। সুতরাং আপনি যদি ব্লক 1 এবং ব্লক 2 এর জন্য বিভিন্ন সারি ব্যবহার করেন বা সেগুলি একই সমবর্তী সারিতে নির্ধারিত করেন তবে সেগুলি একই সাথে চলতে পারে; আপনি যদি তাদের একই সিরিয়াল কাতারে সময় নির্ধারণ করেন তবে তারা সিরিয়ালটি চালাবেন। এটি গ্রুপগুলি ছাড়াই ব্লকগুলির সময় নির্ধারণের চেয়ে আলাদা নয়।
জের্ন ইরিচ

1
এটি কি ওয়েব সার্ভিস পোস্ট কার্যকর করতে প্রযোজ্য?
স্লিপনট

আপনি কি লক্ষ্য করেছেন যে সময়টি আপনার ব্লকে থাকা স্লিপ টাইমের সমান নয়? কেন এমন হবে?
দামন ইউয়ান

2
এআরসি-তে কেবল ডিসপ্যাচ_রিলিজ (গোষ্ঠী) সরান;
loretoparisi

272

জের্ন আইরিচের উত্তরটি প্রসারিত করা (যদি আপনি এই উত্তরটি আপত্তি জানান তবে তার উত্তরটি উপস্থাপন করুন), যদি dispatch_asyncআপনার ব্লকের কলগুলিতে আপনার নিয়ন্ত্রণ না থাকে , যেমন অ্যাসিঙ্ক সমাপ্তি ব্লকগুলির ক্ষেত্রে হতে পারে, আপনি জিসিডি গ্রুপগুলি ব্যবহার করে dispatch_group_enterএবংdispatch_group_leave সরাসরি ।

এই উদাহরণে, আমরা ভান করছি computeInBackgroundএমন কিছু যা আমরা পরিবর্তন করতে পারি না (এটি কল করুন যে এটি একটি ডেলিগেট কলব্যাক, এনএসআরএল সংযোগের সমাপ্তি হ্যান্ডলার বা যাই হোক না কেন) এবং সুতরাং আমাদের প্রেরণ কলগুলিতে অ্যাক্সেস নেই।

// 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!");

এই উদাহরণে, কম্পিউটইনব্যাকগ্রাউন্ড: সমাপ্তি: হিসাবে প্রয়োগ করা হয়:

- (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
@ ureuroburɳ উপরের কোডটি মূল থ্রেডে অপেক্ষা করে। আমি বিশ্বাস করি এটি পুরো থ্রেডটিকে অবরুদ্ধ করবে এবং পুরো গ্রুপটি সম্পূর্ণ না হওয়া অবধি ইউআইকে প্রতিক্রিয়াহীন করে তুলবে। আমি অপেক্ষাটি একটি পটভূমির থ্রেডে স্থানান্তরিত করার পরামর্শ দিচ্ছি। উদাহরণস্বরূপ,
প্রেরণ_গেট_গ্লোবাল_উইউ

2
@ সিবারটেল, ভাল ধরা! আমি আপনার মন্তব্য প্রতিফলিত করতে উদাহরণ কোড আপডেট করেছি। মূল কাতারে থাকার জন্য অনেক সময় আপনার কলব্যাকের প্রয়োজন হয় - সেক্ষেত্রে dispatch_queue_notifyসম্ভবত এটি আরও ভাল (যদি অবরুদ্ধ করার সময়টি স্বল্প সময়ের নিশ্চয়তা না দেওয়া হয়)।
urউরোবারɳ

আমি কোথায় গ্রুপটি মুক্তি করতে পারি (অর্থাত্ প্রেরণ_আগ্রহ (গ্রুপ))? আমি নিশ্চিত না যে এটি ডিসপ্যাচ_গ্রুপ_নোটে প্রকাশ করা নিরাপদ কিনা। গ্রুপটি সম্পূর্ণ হওয়ার পরে যে কোডটি চালানো হচ্ছে সেহেতু আমি কোথায় প্রকাশ করব তা নিশ্চিত নই I'm
জিঞ্জারব্রেডম্যান

: আপনি এআরসি ব্যবহার করে থাকেন তাহলে আপনি কল dispatch_release প্রয়োজন হবে না stackoverflow.com/questions/8618632/...
ɲeuroburɳ

3
চমৎকার পোস্ট যা আরো ব্যাখ্যা করেছেন যে: commandshift.co.uk/blog/2014/03/19/...
Rizon

96

সুইফ্ট 5.1 এর সাহায্যে গ্র্যান্ড সেন্ট্রাল ডিসপ্যাচ আপনার সমস্যা সমাধানের জন্য বিভিন্ন উপায় সরবরাহ করে। আপনার প্রয়োজন অনুসারে, আপনি নিম্নলিখিত প্লেগ্রাউন্ড স্নিপেটগুলিতে প্রদর্শিত সাতটি নিদর্শনগুলির মধ্যে একটি চয়ন করতে পারেন ।


# 1। ব্যবহার DispatchGroup, DispatchGroup'গুলি notify(qos:flags:queue:execute:)এবং DispatchQueueএরasync(group:qos:flags:execute:)

অ্যাপল বিকাশকারী কনকুরન્સી প্রোগ্রামিং গাইড সম্পর্কে এখানে বলা হয়েছে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' গুলি enter()এবং DispatchGroupএরleave()

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()

সোরেশ খানলু দ্য জিসিডি হ্যান্ডবুক ব্লগ পোস্টে নিম্নলিখিত লাইনগুলি লিখেছেন :

একটি সেমফোর ব্যবহার করে, অন্য থ্রেড থেকে একটি সংকেত না পাঠানো পর্যন্ত আমরা একটি নির্বিচার পরিমাণের জন্য একটি থ্রেড ব্লক করতে পারি। অন্যান্য জিসিডির মতো সেমোফোরগুলি থ্রেড-নিরাপদ এবং এগুলি যে কোনও জায়গা থেকে ট্রিগার করা যেতে পারে। যখন আপনাকে একটি সিঙ্ক্রোনাস তৈরি করতে হবে এমন একটি অ্যাসিনক্রোনাস এপিআই রয়েছে সেমাপোরগুলি ব্যবহার করা যেতে পারে, তবে আপনি এটি সংশোধন করতে পারবেন না।

অ্যাপল বিকাশকারী এপিআই রেফারেন্স 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(_:)

অ্যাপল বিকাশকারী এপিআই রেফারেন্স সম্পর্কে বলা হয়েছে 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
 */

প্রত্যেকের জন্য (এবং সেমোফোর ছাড়াই) গ্রুপ.এন্টার () এবং গ্রুপ.leave () ব্যবহার না করে অ্যাসিঙ্ক কলগুলির কোনও সমাধান আছে কি? পছন্দ করুন যদি আমার কোনও সার্ভারে একটি এসিঙ্ক অনুরোধের জন্য অপেক্ষা করতে হয় তবে তার পরে দ্বিতীয় অ্যাসিঙ্ক অনুরোধের জন্য অপেক্ষা করুন। আমি এই নিবন্ধে পড়েছি avanderlee.com/swift/asynchronous-operations কিন্তু আমি ডন এর এটি একটি সহজ ব্যবহার BlockOperation তুলনায় দেখতে
বুনন

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()প্যাডোগোগিক কারণে এই কলগুলিকে যুক্ত করেছি , যাতে ব্লকগুলি দীর্ঘায়িত হয় যাতে আপনি দেখতে পারেন যে সেগুলি একই সাথে চলছে run এই তুচ্ছ উদাহরণে, অনুপস্থিতিতে 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
আপনার এনএসব্লকঅ্যাপেরেশনের কোডটি যখন সিঙ্ক্রোনাস হয় তখন এটি ঠিক। তবে যদি তা না হয় এবং আপনার অ্যাসিঙ্ক অপারেশনটি সম্পন্ন হওয়ার পরে আপনি সম্পূর্ণ ট্রিগার করতে চান?
গ্রেগ ম্যালেটিক

3
@ গ্রেগম্যালেটিক সেই ক্ষেত্রে, আমি একটি NSOperationসাবক্লাস তৈরি করি যা সমকালীন হয় এবং অ্যাসিক্রোনাস isFinishedপ্রক্রিয়াটি সমাপ্ত হলে সেট হয় । তারপরে নির্ভরতা ঠিকঠাক কাজ করে।
রব

@GregMaletic দেখুন stackoverflow.com/questions/18429011/... এবং stackoverflow.com/questions/17426855/... উদাহরণের জন্য।
রব

1
@ গ্রেগম্যালিটিক হ্যাঁ, আপনি এটিও ব্যবহার করতে পারেন (যতক্ষণ dispatch_semaphore_waitনা মূল সারিতে স্থান না নেওয়া হয় এবং যতক্ষণ না আপনার সংকেত এবং অপেক্ষাগুলি ভারসাম্যপূর্ণ থাকে)। যতক্ষণ না আপনি মূল সারিটি অবরুদ্ধ করেন না, ততক্ষণে একটি সেমফোর অ্যাপ্রোচ ঠিক আছে, যদি আপনার অপারেশনগুলির নমনীয়তা প্রয়োজন না হয় (উদাহরণস্বরূপ এগুলি বাতিল করার ক্ষমতা, সামঞ্জস্যের ডিগ্রি নিয়ন্ত্রণের ক্ষমতা ইত্যাদি)।
রব

1
@ রেজা.আব - আপনার যদি টাস্ক দুটি শুরু হওয়ার আগে একটি কাজ শেষ করতে হয় তবে এই কাজের মধ্যে নির্ভরতা যুক্ত করুন। অথবা যদি কিউ সবসময় শুধুমাত্র একটি সময়ে এক কাজের করণ করা হয়, এটা একটি সিরিয়াল কিউ সেটিং দ্বারা করা 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। আপনার দুটি সিগন্যাল রয়েছে, সুতরাং আপনার জন্য দুটি অপেক্ষা করতে হবে। যেমনটি হ'ল আপনার "সমাপ্তি" ব্লকটি প্রথম ব্লকটি সমুদ্রপৃষ্ঠের সংকেত দেওয়ার সাথে সাথে শুরু হবে, তবে অন্য ব্লকটি শেষ হওয়ার আগেই; ২. এটি একটি আইওএস প্রশ্ন ছিল, আমি এর ব্যবহারকে নিরুৎসাহিত করব dispatch_main
রব

1
আমি রবের সাথে একমত এটি কোনও বৈধ সমাধান নয়। dispatch_semaphore_waitযত তাড়াতাড়ি উভয় হিসাবে অবরোধ মুক্ত করবে dispatch_semaphore_signalপদ্ধতি বলা হয়। এই কাজটি প্রদর্শিত হওয়ার কারণটি হ'ল printfব্লকগুলির জন্য 'এক' এবং 'দুটি' তাত্ক্ষণিকভাবে ঘটে এবং printf'অবশেষে' এর জন্য একটি অপেক্ষার পরে ঘটে - এইভাবে ব্লকটি 2 সেকেন্ডের জন্য ঘুমিয়ে যাওয়ার পরে। যদি আপনি sleepকলগুলির পরে প্রিন্টফ রাখেন তবে আপনি 'এক'র জন্য আউটপুট পাবেন, তারপরে ২ সেকেন্ড পরে' অবশেষে ', তারপরে ২ সেকেন্ড পরে' দুই'র জন্য।
urউরোবুর

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

সুইফট ৪.২ উদাহরণ:

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];
    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.