1. .async와 .sync의 차이는 무엇인가?
1.1 DispatchQueue.main.async:
- 비동기적으로 작업을 메인 스레드에 추가합니다.
- 현재 실행 중인 코드가 즉시 반환되고, 메인 스레드의 RunLoop에 따라 작업이 실행됩니다.
- Deadlock(교착상태)이 발생하지 않으며, UI 작업에 안전하게 사용할 수 있습니다.
1.2 DispatchQueue.main.sync:
- 동기적으로 작업을 메인 스레드에 추가합니다.
- 호출한 스레드는 작업이 완료될 때까지 대기합니다.
- 만약 메인 스레드에서 다시 DispatchQueue.main.sync를 호출하면 Deadlock(교착 상태)이 발생합니다.
🟥 .async와 .sync의 차이: 대기 방식
- .async는 "작업을 추가하고 바로 반환"
- .async는 작업을 대기열에 추가한 뒤 즉시 반환합니다. 즉, 호출한 스레드가 이 작업의 완료 여부와 관계없이 다음 작업을 계속 실행합니다.
- 이 때문에 "모든 작업이 끝난 뒤 실행"이 언제일지 몰라도, 호출한 스레드(메인 스레드)는 멈추지 않으므로 Deadlock이 발생하지 않습니다.
- .sync는 "작업을 추가하고 기다림"
- .sync는 작업을 대기열에 추가한 뒤, 해당 작업이 완료될 때까지 호출한 스레드가 기다립니다.
- 이 경우, 메인 큐가 직렬 큐이기 때문에 현재 실행 중인 작업이 끝나지 않으면 대기열의 작업이 실행될 수 없습니다.
- 하지만 .sync는 작업 완료를 기다리기 때문에 호출한 스레드가 멈추며, Deadlock이 발생합니다.
2. 예를 들어서 알아보면
2.1 DispatchQueue.main.async 예제
async는 비동기적으로 작업을 메인 큐에 추가합니다.
이 경우, 현재 실행 중인 코드는 즉시 반환되며, 메인 큐에서 실행될 준비가 되면 작업이 실행됩니다.
func updateUIAsync() {
DispatchQueue.global().async {
// 백그라운드 작업 (예: 네트워크 호출)
let data = "Fetched Data"
print("Background work completed")
// UI 업데이트는 메인 스레드에서
DispatchQueue.main.async {
print("UI updated with data: \(data)")
}
}
}
updateUIAsync()
아래는 출력된 내용입니다.
UI 업데이트를 메인 스레드에서 안전하게 수행하는 일반적인 방식입니다.
Background work completed
UI updated with data: Fetched Data
2.2 DispatchQueue.main.sync 예제
sync는 동기적으로 작업을 메인 큐에 추가하며, 호출한 스레드는 해당 작업이 완료될 때까지 기다립니다.
이 경우, 만약 메인 스레드에서 DispatchQueue.main.sync를 호출하면 Deadlock이 발생합니다.
func updateUISync() {
DispatchQueue.global().async {
// 백그라운드 작업 (예: 데이터 처리)
let data = "Processed Data"
print("Background work completed")
// 동기적으로 UI 업데이트
DispatchQueue.main.sync {
print("UI updated with data: \(data)")
}
}
}
updateUISync()
아래는 출력된 내용입니다.
위 코드에서는 백그라운드 스레드에서 DispatchQueue.main.sync를 호출하므로, 메인 스레드에서 작업을 안전하게 처리할 수 있습니다.
Background work completed
UI updated with data: Processed Data
Deadlock 발생 예제:
아래와 같은 경우, 메인 스레드에서 다시 메인 큐에 동기 작업을 추가하면 Deadlock이 발생합니다.
이유는 메인 스레드가 현재 실행 중인 작업을 완료하기 전에 DispatchQueue.main.sync에서 대기 상태에 빠지기 때문입니다. 이 작업은 절대 완료되지 않으므로 교착 상태가 발생합니다.
func causeDeadlock() {
// 메인 스레드에서 호출
DispatchQueue.main.sync {
print("This will cause a Deadlock!")
}
}
DispatchQueue.main.async {
causeDeadlock()
}
3.실제로 왜 DispatchQueue.main.sync를 잘 사용하지 않는가?
- 대부분의 UI 업데이트는 비동기적으로 처리(async)하는 것이 안전하고 효율적입니다.
- 동기 작업(sync)은 호출한 스레드가 대기하기 때문에 잘못 사용하면 Deadlock의 위험이 있습니다.
- DispatchQueue.main.sync는 꼭 필요한 경우(즉, 작업이 완료된 후에야 다음 코드를 실행해야 하는 경우)에만 신중하게 사용해야 합니다.
4. 권장 사용 방식
- UI 업데이트: 항상 DispatchQueue.main.async를 사용하여 Deadlock 위험을 제거합니다.
- 동기 작업이 꼭 필요할 경우, 백그라운드 스레드에서만 DispatchQueue.main.sync를 사용합니다.
'정보' 카테고리의 다른 글
Static Dispatch vs Dynamic Dispatch (1) | 2024.12.13 |
---|---|
클래스와 구조체가 섞여 있을 때... (0) | 2024.12.13 |
왜 UI가 Main Thread에서만 그려져야 하나? (1) | 2024.12.13 |
프레임워크와 라이브러리 차이 (0) | 2024.11.28 |
객체지향 프로그래밍(OOP)의 주요 개념에 대해 설명해주세요. (0) | 2024.11.23 |