개발콩블로그

[Swift] GCD - 3 DispatchGroup 본문

swift

[Swift] GCD - 3 DispatchGroup

devBean 2025. 2. 4. 22:16

안녕하세요!

개발콩입니다. 오늘은 DispatchGroup 대해서 이어서 알아보도록 하겠습니다.

 

이전 블로그 게시글 내용의 마지막이 비동기 코드는 작업이 끝나는 시점을 특정지을 수 없다는 것에 대해서 말씀드렸습니다.

만약 여러개의 비동기 작업이 동시에 실행되고,

여러 개의 비동기 작업이 모두 끝났을 경우에 특정 동작을 하고 싶을 경우에는 어떻게 할까요?

이러한 작업을 도와줄 수 있는 DispatchGroup에 대해 소개해드리고자 합니다.

 

 

 

 

DispatchGroup

비동기 작업들에 관하여 그룹을 만들고 작업 항목의 실행이 완료되었을 때 완료 핸들러를 실행할 수 있습니다.

👉 여러 비동기 작업들이 실행이 완료되었을 때 원하는 동작을 실행할 수 있도록 도와줍니다.

 

 

 

DispatchGroup 사용방법

DispatchQueue async 메서드로 task 작업을 보낼 때, parameter로 group을 추가하기

let dispatchGroup = DispatchGroup()

DispatchQueue.global().async(group: dispatchGroup) {
    sleep(3)
    print("첫번째 비동기 작업 동작완료")
}

DispatchQueue.global().async(group: dispatchGroup) {
    sleep(4)
    print("두번째 비동기 작업 동작완료")
}

let result = dispatchGroup.wait(timeout: .now() + 30)

switch result {
case .success:
    print("모든 작업이 종료되었습니다.")
case .timedOut:
    print("timeOut")
}

// 1초 경과
// 2초 경과
// 3초 경과 - 첫번째 비동기 작업 동작완료
// 4초 경과 - 두번째 비동기 작업 동작완료
// 4초 경과 - 모든 작업이 종료되었습니다.

 

dispatchGroup에서 wait 메서드를 사용하게 된다면,

비동기 작업에 대해서 동기적으로 작업을 기다릴 수 있습니다.

 

결국 비동기 작업이 모두 끝날 때까지 동기적으로 작업을 기다리게 된다면 우리의 앱은 특정상황에 무한정 기다려야할 수 있습니다.

따라서, timeout에 제한시간을 정할 수 있습니다.

 

하지만 비동기 코드를 사용하는 것은

우리가 해당 작업을 실행하는 동안 다른 작업을 하고 싶다는 의미가 더 큽니다.

이러한 상황에서 모든 작업이 완료될 때까지 동기적으로 기다리는 것은 저는 불필요하다고 생각합니다.

 

아래의 DispatchGroup을 사용하는 또 다른 방법을 소개하면서 다른 메서드를 소개해드리겠습니다.

 

 

 

DispatchGroup의 enter(), leave() 메서드 이용하기

let dispatchGroup = DispatchGroup()

dispatchGroup.enter()
DispatchQueue.global().async(group: dispatchGroup) {
    sleep(2)
    print("첫번째 비동기 작업 동작완료")
    dispatchGroup.leave()
}

dispatchGroup.enter()
DispatchQueue.global().async(group: dispatchGroup) {
    sleep(4)
    print("두번째 비동기 작업 동작완료")
    dispatchGroup.leave()
}

dispatchGroup.notify(queue: .main) {
    print("모든 작업이 종료되었습니다.")
}

// 1초 경과
// 2초 경과
// 3초 경과 - 첫번째 비동기 작업 동작완료
// 4초 경과 - 두번째 비동기 작업 동작완료
// 4초 경과 - 모든 작업이 종료되었습니다.

 

dispatchGroup의 enter() 메서드를 이용하여 작업이 dispatchGroup에 추가되었음을 명시적으로 나타냅니다.

 

이후, 비동기 작업의 수행이 종료되었다면 

dispatchGroup의 leave() 메서드를 이용하여 작업이 종료되었음을 나타냅니다.

단, 여기서 dispatchGroup의 leave()메서드를 먼저 사용하게 된다면 오류가 나게 됩니다.

 

해당 코드에서는 위의 작업과는 다르게

dispatchGroup의 notify 메서드를 사용했습니다.

dispatchGroup의 작업의 count가 0이 될 경우 notify에서 작성된 코드블럭이 실행하게 됩니다.

 

여기서 중요한 점은 실행시킬 동작을 클로저를 통해 전달하는 형식이기 때문에

wait() 메서드와는 다르게 동기적으로 기다리지 않는다는 것입니다.

 

 

 

제 결론 및 느낀점

비동기 코드는 작업이 끝나는 시점을 특정지을 수 없기 때문에

여러 개의 비동기 작업이 모두 끝났을 경우에 대해서

특정 작업을 수행하고 싶은 경우에 사용하는 DispatchGroup에 대해서 알아보았습니다.

 

wait() 메서드의 경우 결국에 동기적으로 작업을 기다리는 것이기 때문에 특정한 상황이 아니라면 잘 사용하지 않을 것 같습니다.

왜냐하면 비동기 작업을 수행하는 이점을 얻을 수 없다고 생각하기 때문입니다.

 

하지만, DispatchQueue의 async 메서드로 task 작업을 보낼 때 group을 지정하는 경우에

notify() 메서드를 사용하게 된다면

비동기 작업의 특성상 실제로 모든 작업이 끝나지 않더라도 notify() 메서드가 실행될 가능성이 있어보입니다.

 

따라서, enter()와 leave() 메서드를 사용하는 경우에 notify() 메서드를 이용할 것 같습니다.

하지만, 이런 경우에는 해당 비동기 코드가 무조건 작업이 종료될 수 있는 가정에서만 사용할 것 같습니다.

 

왜냐하면 끝나지 않은 단 하나의 비동기 작업만으로도 notify() 메서드가 호출되지 않을 수 있기 때문입니다.

 

결국에 이러한 상황을 적절히 판단하고 사용하는 것이 중요하다고 느꼈습니다.