본문 바로가기
🍎 Swift/iOS 학습 노트

[강의노트👩🏻‍💻] 프로세스와 스레드 / 동기 비동기 / Dispatch Queue

by 솔비님 2024. 8. 1.

 

 

1.  프로세스와 스레드

프로세스와 스레드는 모두 컴퓨터에서 작업을 수행하는 흐름과 단위이다
실행 중인 iOS 앱을 프로세스라고 부를 수 있으며, 내부에는 여러개의 스레드가 존재한다

 

 

 

1-1.  프로세스

앱은 iOS에 올라온 프로그램이며, iOS 앱을 실행하면 프로세스라고 한다

(실행하기 위해 메모리에 올라온 프로그램)


*앱을 실행하기 전에는 프로그램이지만 앱을 실행하게 되면 프로세스라고 부른다

 

 

1-2.  스레드

프로세스 내에서 작업을 수행하는 단위이며, 한 개의 프로세스 내에는 여러개의 스레드가 동시에 작업을 수행할 수 있다

크게 메인 스레드와 백 그라운드 스레드로 구분할 수 있고 여러개의 스레드를 가지고 동시에 작업하는 것 멀티 스레딩이라고 한다

 

 

유튜브로 보는 예시

프로그램: 앱에 설치된 유튜브 앱

프로세스: 실행된 유튜브 앱

스레드: 유튜브 앱을 실생하며 필요한 여러가지 단위의 작업들

  • 메인 스레드: 아이폰에 유튜브 UI 를 그리는 작업
  • 스레드 1: 유저의 구독 목록을 불러오는 작업
  • 스레드 2: 서버에서 동영상 정보를 불러오는 작업 등

 


2.  동기와 비동기

 

 

2-1.  동기(Synchronous = sync)

 

작업을 직렬적으로 수행한다

어떠한 스레드에서 작업A를 처리하다가 새로운 작업B가 들어오게 되면

새로운 작업B를 먼저 수행하고 완료된 시점에 기존 작업 A를 수행하는 작업 처리 방식

 

 

동기 처리의 장단점

장점
1. 직관적인 코드 흐름: 코드가 작성된 순서대로 실행되므로 이해하기 쉽다
2. 디버깅이 쉬움: 코드가 순차적으로 실행되므로 문제가 발생한 위치를 파악하기 용이하다
3. 단순성: 비동기 처리보다 코드 구조가 단순하다

단점
1. 응답 시간 증가: 하나의 작업이 완료될 때까지 다음 작업이 시작되지 않으므로, 시간이 오래 걸리는 작업이 있을 경우 전체 응답 시간이 길어질 수 있다
2. 자원 낭비: 긴 시간 대기하는 작업이 있을 경우, 그동안 CPU나 다른 자원이 유휴 상태로 있을 수 있다
3. 블로킹: 긴 작업이 진행되는 동안 다른 작업이 블록되어 시스템 전체 성능이 저하될 수 있다

 

 

 

2-2.  비동기(asynchronous = async)

 

작업을 병렬적으로 수행한다

어떠한 스레드에서 작업A를 처리하다가 새로운 작업B가 들어오게 되면

다른 스레드에게 새로운 작업B를 넘기고 기존 작업A는 멈추지 않고 동시에 수행한다

다른 스레드에 넘긴 작업B가 완료되면 결과를 전해받는다

 

 

비동기 처리의 장단점

장점
1. 효율적인 자원 활용: 긴 시간 대기하는 작업이 있을 때도 다른 작업을 병렬로 처리할 수 있어 자원을 효율적으로 사용할 수 있다
2. 응답 시간 단축: 일부 작업이 대기 상태에 있어도 다른 작업을 동시에 진행할 수 있어 전체 응답 시간이 단축된다
3. 유연성: 여러 작업을 동시에 처리할 수 있어 다양한 작업을 동시에 수행할 때 유리하다

단점
1. 복잡성 증가: 코드가 순차적으로 실행되지 않기 때문에 코드 흐름이 복잡해지고 이해하기 어려울 수 있다
2. 디버깅이 어려움: 비동기 코드의 실행 순서를 추적하기 어렵기 때문에 디버깅이 어려울 수 있다
3. 콜백 지옥: 콜백 함수를 남발하게 되면 코드가 매우 복잡해지고 유지보수가 어려워질 수 있다
이를 방지하기 위해서는 Promise나 async/await 같은 패턴을 사용하는 것이 좋다

 

 


3.  Dispatch Queue

애플의 공식문서에서 GCD(Grand Central Dispatch)는 동시성 프로그래밍을 돕는 프레임워크로 명시된다
*동시성 프로그래밍이란 여러가지 일을 동시에 작업하도록 하는 프로그래밍

 

Swift 에서 사용하는 GCD 기술로는 Dispatch Queue가 있으며,

멀티 스레딩 작업을 하며 비동기적으로 여러가지 작업을 수행하기 위하여 사용된다

  • Dispatch : 보내다, 발송하다
  • Queue : 자료구조 중 큐(선입선출)

 

 

과거에는 멀티 스레딩과 비동기 작업을 하기 위해서는 개발자가 직접 스레드를 생성하고 작업을 할당해 주었다(복잡성)

하지만 현재 Dispatch Queue에 그저 작업을 넘겨주기만 하면 운영체제가 적절한 스레드에 작업을 할당하게 된다

따라서 실수할 여지가 줄어들게 되고 개발자의 수고가 덜어졌다

 

 

 

3-1.  DispatchQueue 종류 

 

기본적인 코드 형태는 아래와 같다

DispatchQueue.{큐종류}.{qos옵션}.{sync/async} {
		// 수행할 작업 코드 작성
}
// 큐 종류: Main / Global / Custom
// qos: Quality Of Service
// sync: 동기적으로 작업 수행
// async: 비동기적으로 작업 수행

 

 

1.  메인 큐 (Main Queue)

DispatchQueue.main.async {
    // UI 업데이트 코드
    self.label.text = "작업 완료!"
}

* UI 업데이트와 관련된 작업을 처리하며 앱의 메인 스레드에서 실행된다

* Serial Queue (직렬 큐)

 : 들어온 작업들은 한 가지 쓰레드에 모두 보내 큐에 추가된 작업을 한 번에 하나씩 순서대로 실행

 : 쓰레드 하나에 모든 작업을 할당하기 때문에 작업 완료 순서가 보장됨

 

 

2.  글로벌 큐 (Global Queue)

DispatchQueue.global().async {
    // 네트워크 통신 또는 계산이 무거운 작업을 백그라운드에서 수행
    let result = self.someHeavyComputation()
    
    DispatchQueue.main.async {
        // 결과를 메인 스레드에서 UI에 반영
        self.updateUI(with: result)
    }
}

* 백그라운드 작업을 처리

* Concurrent Queue (동시성 큐)

 : 큐에 추가된 여러 작업을 동시에 실행할 수 있으며 여러 스레드에서 작업이 동시에 병렬적으로 실행 가능

 : 작업의 완료 순서는 보장되지 않음

 

 

3.  커스텀 큐 (Custom Queue)

// label 에 큐의 고유한 이름 설정.
// attributes 에 serial/concurrent 설정.
// 설정하지 않으면 default 값은 serial.
let customQueue = DispatchQueue(
		label: "com.myapp.customqueue", 
		attributes: .concurrent
)

customQueue.async {
    // 커스텀 큐에서 실행할 작업
}

* 개발자가 직접 생성하고 관리하는 큐

* 직렬(Serial) 또는 동시(Concurrent) 큐로 설정 가능