study record
[Swift] Dispatch Queues 본문
본 글은 해당 링크(공식 사이트) 글을 해석하여 정리한 글입니다.
Grand Central Dispatch (GCD) dispatch queues는 테스크들을 수행하는 데에 강력한 툴이다. Dispatch queues는 호출자를 존중하며 비동기적으로나 동기적으로 코드의 블록들을 실행하게 한다. dispatch queues를 분리된 스레드에 수행하게끔 사용할 수 있다.
dispatch queues의 장점은 사용하기에 단순하고 효율적이라는 것이다.
이 챕터에서는 dispatch queues에 소개와 어플리케이션에서 일반적인 테스크를 실행하고자 할 때 어떻게 사용하는지를 담고 있다. 만약 존재하는 스레드 코드를 dispatch queues로 바꾸고 싶다면, 추가적인 팁을 Migrating Away from Threads에서 얻을 수 있다.
About Dispatch Queues
Dispatch Queues는 어플리케이션에서 비동기적으로, 동기적으로 테스크를 수행하기 위한 쉬운 방법이다. 테스크는 단순히 어플리케이션이 수행하기 위해 필요한 작업이다. 예를 들어, 어떤 계산을 수행하기 위한 테스크, 파일로부터 데이터를 읽어오기 등이 있다. 이를 정의하기 위해 상응하는 코드를 함수 안에 또는 block 안에 정의하고 디스패치큐에 추가하면 된다.
디스패치큐는 제출한 테스크를 관리하는 객체와 같은 구조이다. 모든 디스패치큐는 first in first out 데이터 구조이다. 그러므로, 큐에 추가한 테스크는 추가된 순서대로 시작하게 된다. GCD는 자동적으로 몇몇 디스패치큐들을 제공한다. 이들을 특별한 목적으로 만들어낼 수도 있다. 아래는 이용가능한 디스패치큐들의 종류와 사용방법이다.
Types of dispatch queues
1. Serial
Serial 큐는 큐에 추가된 순서대로 한 번에 하나의 테스크를 실행한다.
현재 실행하는 테스크가 특정 스레드에서 돌아간다. 시리얼큐는 종종 특정 자원에 대한 접근을 동기화하기 위해 사용된다.
필요한만큼 많은 시리얼큐를 만들어낼 수 있고, 각 큐는 동기적으로 각 큐들을 존중한다. 다시 말해, 만약 시리얼 큐들을 만든다면, 각 큐는 한 번에 하나의 테스크를 실행하나 4개의 테스크까지 동기적으로 실행될 수 있다. 더 많은 정보는 Creating Serial Dispatch Queues.
2. Concurrent
Concurrent 큐는 global dispatch queue의 타입으로 알려졌다. Concurrent큐는 하나 또는 그 이상의 테스크들을 동시에 실행한다. 그러나 테스크들은 여전히 큐에 더해진 순서대로 시작한다. 현재 실행하는 테스크가 특정 스레드에서 실행한다. 실행하는 테스크들의 정확한 숫자는 가변적이고 시스템 컨디션에 의존한다.
iOS5 그 이후에 concurrent dispatch queue를 DISPATCH_QUEUE_CONCURRENT를 큐타입으로 정의하면 스스로 만들 수 있게 되었다. 게다가 어플리케이션에서 사용하기 위해 global concurrent queue가 네가지 미리 정의되어 있다. 더 많은 global concurrent queues의 정보는 Getting the Global Concurrent Dispatch Queues.
3. Main dispatch queue
main dispatch queue는 전역적으로 이용가능한 어플리케이션의 메인 스레드 위의 작업들을 실행하는 시리얼 큐이다. 이 큐는 어플리케이션의 run loop에 작업한다. 그 이유는 어플리케이션의 메인 스레드에서 실행하므로 메인 큐는 종종 어플리케이션의 주요 동기화 포인트로서 사용되기 때문이다.
비록 메인 디스패치큐를 만들 필요는 없지만 적절하게 어플리케이션이 돌아가도록 확인하는 것이 필요하다. 이 큐 관리에 대한 더많은 정보는 Performing Tasks on the Main Thread.
어플리케이션에 동기성을 추가하고자할 때, 디스패치큐는 몇몇 이점들을 제공한다.
가장 직접적인 이점은 단순히 work-queue programming model의 단순성이다. 스레드들과 함께 수행하고자 하는 작업과 스레드 관리 생성의 코드가 필요할 것이다. 디스패치큐는 스레드의 생성과 관리에 대해 걱정하는 것 없이 원하는 수행에만 집중하게끔 한다. 대신에, 시스템이 모든 스레드 생성과 관리를 핸들링한다. 이 이점은 시스템이 하나의 어플리케이션이 하는 것보다 스레드를 더 효율적으로 관리할 수 있다는 것이다. 시스템은 스레드의 수를 이용가능한 자원과 현재 시스템 상태를 통해 동적으로 파악한다. 게다가, 시스템은 직접 스레드를 만드는 것보다 테스크를 빠르게 시작할 수 있다.
비록 디스패치큐를 위한 코드를 다시 짜는 것이 어려울 수 있겠지만 쓰레드를 위한 코드를 스스로 짜는 것보다 더 쉬울 것이다. 코드 작성의 핵심 키는 테스크를 디자인하고 비동기적으로 동작하는 것이다. 그러나, 디스패치 큐가 이점을 가지는 곳은 예측가능성 안에 있다. 만약 다른 스레드에서 같은 공유 자원에 접근하는 두 가지 테스크를 가진다면, 그 자원을 어떤 한 스레드에서 먼저 수정하고 동시에 그 자원을 수정하지 못하도록 lock을 사용할 필요가 있을 수 있다. 디스패치큐와 함께, 주어진 시간에 자원을 수정하는 테스크를 두 가지 테스크가 하지 못하도록 serial dispatch queue를 추가할 수 있다. 큐 베이스 동기화 유형은 lock보다 더 효율적이다. 그 이유는 lock은 항상 비싼 커널 트랩을 필요로 한다. 반면에 디스패치 큐는 어플리케이션의 프로세스 공간에서 작동하고, 오직 필요할 때에만 커널을 부르기 때문이다.
비록 시리얼 큐에서 두 가지 테스크를 작동하는 것은 동시에 실행을 못 시킨다는 점을 가리킬 수 있지만, 만약 두 스레드가 동시에 lock을 가지게 된다면, 어떤 동시성도 잃거나 줄여지게 될 것이다. 더 중요한 것은 스레드 모델은 두 가지 스레드 생성을 필요로 한다. 이것은 커널과 유저 공간 메모리 사이에서 이루어진다. 디스패치 큐는 스레드들을 위해 같은 메모리 페널티를 부과하지 않고, 사용하는 스레드들을 바쁘게 유지하고 블락하지 않는다.
디스패치 큐의 기억하기 좋을 핵심 포인트들
- 디스패치 큐는 다른 디스패치 큐를 존중하며 동시적으로 실행한다. 테스크의 일련화는 같은 디스패치 큐 안에서 제한된다.
- 시스템은 주어진 시간에 전체 테스크 수를 결정한다. 그러므로 100가지 다른 큐에서 100가지 테스크를 가진 앱은 동시적으로 모든 테스크를 실행하지 않을지도 모른다.
- 시스템은 큐의 우선순위 레벨을 담당하여 시작할 새 테스크를 선택한다. 더 많은 정보는 Providing a Clean Up Function For a Queue.
- 큐의 테스크는 큐에 추가된 그 시간에 실행할 준비가 되어야 한다.
- Private 디스패치 큐는 참조 카운트 객체이다. 코드에 큐를 추가하면 디스패치 소스가 큐에 추가되고, retain count가 올라가게 된다. 그러므로 디스패치 자원들을 취소하고 retain 호출이 적절하게 균형을 맞추도록 해야 한다. 더 많은 정보는 Memory Management for Dispatch Queues.
'Swift > 스위프트 정리' 카테고리의 다른 글
[Swift] DispatchSemaphore - Swift에서 세마포어 사용하기! (0) | 2024.05.28 |
---|---|
[Swift] Creating and Managing Dispatch Queues (0) | 2023.02.13 |
[Swift] Swift 고차함수(map 시리즈, reduce, filter) (0) | 2023.01.30 |
[Swift] Combine 연산자와 CheckedContinuation (0) | 2023.01.29 |
[Swifit] Combine 기본 예제 (0) | 2023.01.15 |