Thread와 Run Loop

Jisu·2023년 9월 7일
0

iOS

목록 보기
6/9
post-thumbnail

Thread

앱에서 특정 기능을 수행할 때, 그러니까 http 통신을 요청한다던가, 뷰를 업데이트 시킨다던가 하는 그런 것들의 최소 작업 단위는 Threa이다. Thread가 처리하는 작업을 태스크라고 부르며 Thread는 한번에 하나의 태스크를 처리한다.

Thread를 검색하면 나오는 기본 정의는 프로세스 내에서 실행되는 흐름의 단위이다. iOS 앱 또한 프로세스의 일종이니, 위에서 언급한 설명도 Thread 정의에서 크게 벗어나지는 않는다.

Main Queue, Global Queue

애플은 비동기처리 프레임워크인 GCD를 지원한다. 우리가 수행하려는 작업은 코드 블록 단위로 Queue에 배정할 수 있다.

Queue는 3가지 종류가 잇다.

Main Queue

UI와 관련한 내부 태스크를 serial하게 수행하는 Main Queue
내부 태스크를 직렬 수행하므로 하나의 쓰레드에서 태스크가 수행되는데 이를 메인쓰레드라고 부른다.

Global Queue

내부 태스크를 Concurrent하게 처리하는 Global Queue
여러 태스크를 병렬 수행할 수 있기 때문에 여러개의 쓰레드를 생성한다.

Custom Queue

기본으로 Serial 처리지만 concureent도 설정가능한 커스텀큐

이렇게 3가지 queue에 개발자는 작업을 비동기, 동기로 배정할 수 있는 것이다. 단, 메인큐는 데드락이 걸리기 때문에 동기 작업을 배정할 수 없다.


Main Queue

    private func removeBandSelectMenu() {
        DispatchQueue.main.async { [weak self] in
            self?.animate { [weak self] in
                self?.bandSelectMenuView.frame = CGRect(
                    x: (self?.view.frame.origin.x ?? 0) + 15,
                    y: (self?.view.frame.origin.y ?? 0) + 67,
                    width: 250,
                    height: 0
                )
            }
        }
    }

Global Queue

DispatchQueue.global().async {
        print("First")
}

DispatchQueue.global().async {
        print("Second")
}

DispatchQueue.global().async {
        print("Third")
}

//First
//Second
//Third

### 글로벌 큐는 병렬이므로 print문의 코드 실행 순서대로 찍히지 않는 것을 볼 수 있다.

Custom Queue

private let sessionWatcher: SessionWatcher = SessionWatcher(queue: DispatchQueue(label: "Hello"))

Run Loop

런루프는 소켓, 파일, 마우스 등 입력 소스를 처리하는 이벤트 처리루프 (객체) 모든 쓰레드가 가지고 있다.
GCD를 통해 쓰레드를 생성하고 태스크를 배정할 수 있다. 그런데 만약 이렇게 생성된 쓰레드에 다른 입력이나 Timer를 주고 싶다면 직접 각 쓰레드의 런루프 객체에 접근해서 원하는 입력 및 Timer를 설정해주고 런루프를 실행해야한다.

위 그림과 같이 쓰레드는 Input source 및 Timer source를 받아 런루프 내에서 처리하게 된다.

DispatchQueue.global().async {
    let runLoop = RunLoop.current
    Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { _ in
        print("First")
    }
    runLoop.run()
}

다음과 같이 글로벌큐가 작업을 수행하기 위해 쓰레드를 만들었다면 RunLoop.current를 통해 접근해서 Timer를 설정해줄수 있다.
여기서 Timer를 설정한 이후 직접 수동으로 runLoop를 run해줘야하는 것을 볼 수 있다. 메인쓰레드를 제외한 모든 쓰레드는 외부 소스를 주입할 때는 직접 런루프에 접근하고 run해줘야 한다.

Main Event Loop

메인 쓰레드는 UI와 관련된 작업을 처리하고, 사용자 인터페이스의 업데이트와 이벤트 처리를 담당한다. 메인쓰레드도 마찬가지로 런루프를 가지고 있는데 Main Event Loop 불린다.

메인쓰레드가 다른 쓰레드와 다른 것은 RunLoop를 수동으로 run해줄 필요가 없다는 것이다. 내부적으로 반복적으로 run을 호출하고 있기 때문이다.

메인 쓰레드에서 UI 업데이트 및 이벤트 처리를 자동으로 담당하도록 정해놓음으로서 일관성있는 UI를 보여주고 개발자들에게는 혼란을 방지할 수 있다는 장점이 있다.

Reference

Run loop 관련 정리1
Run loop 관련 정리2
Main Event Loop - Apple Documentation

profile
비즈니스에 관심많은 DevOps Engineer 장지수입니다.

0개의 댓글