관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 2. 타임아웃 처리 방법 - DispatchGroup 사용 (+ async 처리를 순서대로 처리 방법) 본문

iOS 응용 (swift)

[iOS - swift] 2. 타임아웃 처리 방법 - DispatchGroup 사용 (+ async 처리를 순서대로 처리 방법)

jake-kim 2023. 4. 6. 01:58

1. 타임아웃 처리 방법 - DispatghWorkItem 사용

2. 타임아웃 처리 방법 -  DispatchGroup 사용 (+ async 처리를 순서대로 처리 방법) <

(async 작업이 하나이면 DispatchWorkItem을 사용하고, async 작업이 두 개 이상이면 DispatchGroup 사용)

DispatchGroup 개념

  • async 작업들을 sync 처럼 처리할 수 있도록 하는 역할
  • sync하게 group으로 넣은 작업들이 끝날때까지 기다리며, 따로 time out처리도 가능

https://developer.apple.com/documentation/dispatch/dispatchgroup

DispatchGroup으로 async작업들을 sync하게 만들기

  • 예제에 사용될, async하게 호출되어야할 메소드 준비
func task1(completion: (Int) -> ()) {
    print("start task1", Thread.current)
    sleep(3)
    print("end task1", Thread.current)
    completion(1)
}

func task2(completion: (Int) -> ()) {
    print("start task2", Thread.current)
    sleep(5)
    print("end task2", Thread.current)
    completion(2)
}

let tasks = [task1, task2]
var results = [Int]()
  • DispatchGroup과 DispatchQueue 인스턴스 생성
    • DispatchQueue를 생성하는 이유: 뒤에서 wait코드와 타임아웃을 넣을것이기 때문에, 현재 스레드에서 작업 처리도하고 wait가 걸리면 deadlock이 발생하기 때문에 작업은 별도의 스레드에서 처리하기 위함
let group = DispatchGroup()
let queue = DispatchQueue(label: "my_task")
  • for문을 돌면서 수행
    • 작업이 시작될땐 group.enter() 사용
    • 작업이 끝날땐 group.leave() 사용
    • 작업을 타임아웃 걸땐 group.wait(timeout: .now() + .seconds(30)) { ... }
    • wait(timeout:) 호출하는 스레드와 leave()를 호출하는 스레드가 달라야 deadlock이 발생 안하므로 queue.async로 두 스레드가 다르게 처리
for (i, task) in tasks.enumerated() {
    print("queue.async's out thread:", Thread.current) // <_NSMainThread: 0x60000325c880>{number = 1, name = main}
    group.enter()
    queue.async {
        print("queue.async's in thread:", Thread.current) // <NSThread: 0x60000325a980>{number = 4, name = (null)}
        task { result in
            results.append(result)
            group.leave()
        }
    }
    
    switch group.wait(timeout: .now() + .seconds(30)) {
    case .success:
        print("작업이 성공")
        continue
    case .timedOut:
        print("작업이 타임아웃 되었습니다.")
        return
    }
}

(결과)

/*
queue.async's out thread: <_NSMainThread: 0x600001cfc440>{number = 1, name = main}
queue.async's in thread: <NSThread: 0x600001ca4080>{number = 7, name = (null)}
start task1 <NSThread: 0x600001ca4080>{number = 7, name = (null)}
end task1 <NSThread: 0x600001ca4080>{number = 7, name = (null)}

(... 3초후)
작업이 성공

queue.async's out thread: <_NSMainThread: 0x600001cfc440>{number = 1, name = main}
queue.async's in thread: <NSThread: 0x600001ca4080>{number = 7, name = (null)}
start task2 <NSThread: 0x600001ca4080>{number = 7, name = (null)}
end task2 <NSThread: 0x600001ca4080>{number = 7, name = (null)}
(... 5초후)

작업이 성공

group.notify
result> [1, 2] <NSThread: 0x600001ca4080>{number = 7, name = (null)}
*/

* 전체 코드: https://github.com/JK0369/ExTimeout_dispatchGroup

* 참고

https://developer.apple.com/documentation/dispatch/dispatchgroup

Comments