안녕하세요, 루피입니다.
오늘은 Concurrency의 핵심 개념인 메인 스레드에 대해 알아보겠습니다.
모든 프로그램의 시작점, 메인 스레드
모든 프로그램은 실행될 때 최소 하나 이상의 Thread를 갖게 되는데, 이 첫 번째 스레드를 바로 Main Thread라고 부릅니다.
간단한 커맨드라인 앱은 메인 스레드 하나만으로 모든 작업을 마칠 수 있지만, iOS 앱처럼 복잡한 프로그램은 여러 스레드를 사용합니다. 하지만 어떤 경우든, 앱이 실행되는 동안 메인 스레드는 항상 존재합니다.
UI 작업은 메인 스레드에서
가장 중요한 규칙입니다. 모든 UI 관련 작업(은 반드시 메인 스레드에서 처리해야 합니다. '가끔'이 아니라 '항상'입니다. 만약 다른 스레드에서 UI를 업데이트하려고 하면 어떻게 될까요?
- 아무 일도 일어나지 않거나
- 앱이 예기치 않게 종료되거나 (Crash)
- 화면이 깨지는 등 이상하게 동작할 수 있습니다.
이 규칙은 iOS, macOS, tvOS, watchOS를 포함한 모든 Apple 플랫폼 개발에 적용되는 철칙입니다.
스레드를 직접 만들지 않는 이유
Swift에서는 필요하면 스레드를 직접 만들 수 있지만, 실제로는 거의 그렇게 하지 않습니다. 스레드를 직접 다루면 복잡성이 기하급수적으로 늘어나기 때문입니다.
- Context Switch 비용: CPU는 여러 스레드를 번갈아 가며 실행합니다. 이때 한 스레드의 상태를 저장하고 다른 스레드의 상태를 불러오는 과정을 '컨텍스트 스위치'라고 하며, 이 과정은 눈에 보이지 않는 성능 저하를 유발합니다.
- Thread Explosion : CPU 코어의 수보다 훨씬 많은 스레드를 생성하면, 시스템은 스레드를 관리하는 데에만 너무 많은 자원을 소모하게 되어 오히려 전체적인 성능이 떨어집니다.
이러한 이유로 현대 프로그래밍에서는 스레드를 직접 다루기보다 Queue 를 통해 작업을 관리하는 방식을 선호합니다.
스레드 대신 '큐(Queue)'로 생각하기
스레드가 '작업을 실행하는 주체'라면, 큐는 '처리할 작업들의 작업 목록'과 같습니다.
큐를 사용하는 것이 더 쉬운 이유는 우리가 '무엇을' 할 것인지에만 집중할 수 있기 때문입니다. 작업이 실제로 어떤 CPU 코어에서 어떻게 실행되는지에 대한 복잡한 관리는 시스템(GCD)에 맡기고, 우리는 단지 작업을 큐에 보낼 뿐입니다.
- Serial 큐: 작업을 순서대로 하나씩 처리
- Concurrent 큐: 작업을 동시에 여러 개 처리
심지어 많은 경우, 직접 큐를 만들 필요도 없이 시스템이 제공하는 기본 큐를 사용하면 충분합니다.
메인 스레드 vs. 메인 큐
메인 스레드와 메인 큐는 혼용되지만, 엄밀히 말해 둘은 다릅니다. 이 차이점은 평소에는 문제 되지 않지만, 복잡한 상황에서는 중요할 수 있습니다.
- Main Queue는 보장된 길입니다.
메인 큐에 보낸 작업은 항상 메인 스레드에서 실행되는 것이 보장됩니다. 그래서 우리가 UI 작업을 할 때DispatchQueue.main을 사용하는 것입니다. - 메인 스레드는 가끔 다른 길의 작업을 처리합니다.
메인 스레드에서 실행 중인 코드라고 해서, 그 작업이 반드시 메인 큐에서 온 것은 아닐 수 있습니다. 시스템은 효율성을 위해 다른 큐의 작업을 메인 스레드로 가져와 실행할 수도 있습니다.
따라서 UI 작업을 할 때는 현재 스레드가 메인 스레드인지 확인하는 것보다, 작업을 DispatchQueue.main에 보내는 것이 가장 확실하고 안전한 방법입니다.
오늘도 화이팅입니다!
'iOS > Swift' 카테고리의 다른 글
| [Swift] Concurrency - Task(2) (1) | 2025.06.07 |
|---|---|
| [Swift] Concurrency - Task(1) (2) | 2025.06.07 |
| [Swift] 동시성 vs 병렬성 (0) | 2025.02.26 |
| [Swift] Dispatch Work Item (0) | 2025.02.24 |
| [Swift] Dispatch Group (0) | 2025.02.23 |