다른 블록을 시작하기 전에 두 개의 비동기 블록이 실행될 때까지 기다리는 중
GCD를 사용할 때는 2개의 비동기 블록이 실행되어 완료될 때까지 기다렸다가 다음 실행 단계로 넘어갑니다.그것을 하는 가장 좋은 방법은?
다음을 시도했지만 효과가 없는 것 같습니다.
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
});
디스패치 그룹 사용: Apple iOS Developer Library 동시성 프로그래밍 가이드의 "디스패치 큐" 장에 있는 "큐잉 태스크 그룹 대기 중"의 예를 보려면 여기를 참조하십시오.
예를 들어 다음과 같습니다.
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
답변에 자세히 설명하겠습니다(답변을 상향 투표합니다). 이 Jörn Eyrich를 수). 만약 당신이 이 답변에 대한 통제권을 가지고 있지 않다면dispatch_async
블록의 할 수 .dispatch_group_enter
★★★★★★★★★★★★★★★★★」dispatch_group_leave
직접적으로.
예에서는 우리가 을 하고 computeInBackground
「」( 「NSURLC Connection completion Handler」, 「NSURLC Connection completion Handler」)에 대해 설명합니다.
// 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:completion:이 구현되어 있습니다.
- (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!
Swift 5.1에서는 Grand Central Dispatch가 고객의 문제를 해결하는 다양한 방법을 제공합니다.필요에 따라 다음 Playground 스니펫에 표시된 7가지 패턴 중 하나를 선택할 수 있습니다.
#1. 사용방법,DispatchGroup
및 의
Apple Developer Concurency Programming Guide 에는 다음과 같이 기술되어 있습니다.
디스패치 그룹은 하나 이상의 태스크 실행이 완료될 때까지 스레드를 차단하는 방법입니다.이 동작은 지정된 태스크가 모두 완료될 때까지 진행할 수 없는 장소에서 사용할 수 있습니다.예를 들어 일부 데이터를 계산하기 위해 여러 작업을 디스패치한 후 그룹을 사용하여 해당 작업을 기다린 다음 작업이 완료되면 결과를 처리할 수 있습니다.
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
및DispatchGroup
의
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. 및 의 사용방법barrier
Grand Central Dispatch Tutorial for Swift 4: Raywenderlich.com의 Part 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. , 및 의 사용
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
의
Soroush Khanlu는 The GCD Handbook 블로그 투고에 다음과 같은 글을 남겼다.
세마포를 사용하면 다른 스레드에서 신호가 전송될 때까지 임의의 시간 동안 스레드를 차단할 수 있습니다.세마포어는 GCD의 다른 부분과 마찬가지로 스레드 세이프하며 어디서든 트리거가 가능합니다.세마포어는 동기화가 필요한 비동기 API가 있을 때 사용할 수 있지만 수정할 수는 없습니다.
또한 Apple Developer API Reference는 다음 사항에 대해 설명합니다.DispatchSemaphore
init(value:)
이니셜라이저:
값에 0을 넘기는 것은 두 스레드가 특정 이벤트의 완료를 조정해야 할 때 유용합니다.0보다 큰 값을 전달하면 풀 크기가 값과 동일한 유한 리소스 풀을 관리하는 데 유용합니다.
사용방법:
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. 및 사용방법Operation
의
에는 Apple Developer API Reference에 대해 되어 있습니다.OperationQueue
:
에서는 " " 가 됩니다.
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
(iOS 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
*/
또 다른 GCD 대안은 장벽입니다.
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");
});
동시 큐를 생성하여 2개의 블록을 디스패치한 후 장벽이 있는 최종 블록을 디스패치하면 나머지 2개의 블록이 완료될 때까지 대기합니다.
대해 건 GCD로 해주세요.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];
한 . 을 스레드에서 할 때 합니다. 그룹은 사용자가 사용할 때 입력한 스레드에서 작업(블록)을 실행합니다.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
원하는 걸 얻을 수 있어요
첫 번째 답변은 기본적으로 정확하지만 원하는 결과를 얻기 위한 가장 간단한 방법을 원하는 경우 세마포어를 사용하여 수행하는 방법을 보여주는 독립형 코드 예를 다음에 제시합니다(이것은 디스패치 그룹의 백그라운드 작업 방식이기도 합니다).
#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();
}
Swift 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
}
}
신속한 답변 수용:
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)
다른 답변이 좋지 않은 것은 아니지만 Google에서 항상 사용하고 있는 토막입니다.
- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {
if (signInDoneSel) {
[self performSelector:signInDoneSel];
}
}
언급URL : https://stackoverflow.com/questions/11909629/waiting-until-two-async-blocks-are-executed-before-starting-another-block
'programing' 카테고리의 다른 글
데이터베이스 다이어그램 지원 개체를 설치할 수 없습니다...유효한 소유자가 없습니다. (0) | 2023.04.11 |
---|---|
지정된 값을 포함하는 열의 VBA 셀 수 (0) | 2023.04.11 |
NSUserDefaults에 문자열을 저장하시겠습니까? (0) | 2023.04.11 |
\d는 grep의 기본 표현식에서는 지원되지 않습니까? (0) | 2023.04.11 |
MongoDB, 어레이에서 객체 삭제 (0) | 2023.04.06 |