적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Swift iOS 앱 개발/iOS

[Swift GCD] GCD(Grand Central Dispatch)

hongssup_ 2023. 2. 9. 23:57
반응형
멀티코어 환경에서 프로그램의 성능과 반응성을 높이고 더욱 효과적으로 사용할 수 있도록, 시스템 수준에서
GCD가 디스패치 큐를 이용해 multi threading을 지원하고 동시 작업을 관리해준다.
디스패치 큐는 작업들이 여러 쓰레드에서 동기적 or 비동기적으로 동작하며 동시에 일을 할 수 있도록, 큐(Queue)를 이용해 작업을 분산 처리 하는 FIFO 대기열이다. 
디스패치 큐의 종류에는 main, global, private 큐가 있다.
main 큐에서 실행되는 main thread는 iOS 에서 오직 하나만 존재하고, 모든 UI 작업들이 이 메인 쓰레드에서 처리된다. 
메인 큐는 한 번에 하나의 task 밖에 실행하지 못하는 serial 큐이기 때문에, UI 실행에 영향을 끼칠 수 있는 네트워크 호출처럼 시간이 오래 걸리는 작업들의 경우,  글로벌 큐에서 비동기적으로 구현하는 것이 좋다. 
global 큐에서는 처리 우선 순위를 설정할 수 있도록 QoS(Quality of Service) 파라미터를 제공한다. 

 

1. GCD란?

Dispatch = GCD = Grand Central Dispatch (Framework)
: execute code concurrently on multicore hardware by submitting work to dispatch queues managed by the system. 
GCD란 디스패치 큐를 이용해 multi threading을 지원하고 동시 작업을 관리하는 것.

* cuncurrently : 동시에

멀티코어 환경에서 프로그램의 성능과 반응성을 높이고 최적화할 수 있도록, 시스템 수준에서 GCD가 디스패치 큐를 이용해 multi threading을 지원하고 동시 작업을 관리해준다.

 

2. DispatchQueue 란?

DispatchQueue 
: FIFO queues, that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread. 
작업들이 여러 쓰레드에서 동기적 or 비동기적으로 동작하며 동시에 일을 할 수 있도록, 큐(Queue)를 이용해 작업을 분산 처리 하는 FIFO 대기열이다. 

Dispatch queues execute tasks either serially or concurrently. Work submitted to dispatch queues executes on a pool of threads managed by the system. 

디스패치 큐는 작업들을 순차적으로 또는 동시에 실행한다. 디스패치 큐에 넘겨진 작업은 시스템에서 관리하는 쓰레드 풀에서 실행된다.

You schedule work items synchronously or asynchronously. When you schedule a work item synchronously, your code waits until that item finishes execution. When you schedule a work item asynchronously, your code continues executing while the work item runs elsewhere.

개발자는 개별 작업 항목을 동기식 또는 비동기식으로 예약을 한다. 작업을 동기식으로 설정하면 해당 작업의 실행이 완료될 때까지 코드가 대기하고, 작업을 비동기식으로 설정하면 작업이 다른 곳에서 실행되는 동안 코드가 계속 실행된다.

 

** Attempting to synchronously execute a work item on the main queue results in deadlock.

메인 큐에서 작업을 동기식으로 실행하려고 하면 교착상태가 발생한다. 

 

과도한 쓰레드 생성 주의

For serial tasks, set the target of your serial queue to one of the global concurrent queues. That way, you can maintain the serialized behavior of the queue while minimizing the number of separate queues creating threads.

직렬 작업들의 경우, 글로벌 하나를 직렬 큐로 정하고 사용하면 서로 다른 큐에서 각자의 스레드를 생성하는 것을 최소화하고 직렬로 작업을 수행할 있다. 

 

3. DispatchQueue 종류와 특성

- Main Queue

- Global Queue

- Private(Custom) Queue

 

Main Queue (Serial Queue)

The dispatch queue associated with the main thread of the current process. (= Main Thread)

iOS에서 Main Thread는 오직 한 개만 존재. UI 작업들은 메인 쓰레드에서 Serial 처리가 . 

작성 코드가 cocoa에서 실행될 때 main thread에서 호출.

모든 UI 작업은 메인 스레드에서 처리해야. (어떤 OS 에서든 UI 처리하는 일은 하나의 쓰레드에서만 처리해야.)

main thread는 main queue에서 실행되는데 main queue는 한번에 하나의 task 밖에 실행하지 못하는 serial queue이기 때문에 UI 실행에 영향을 줄 만한 코드들(시간이 걸린다거나)은 main thread가 아닌 global thread로 실행시켜줘야 한다. 

앱에서 서버와 통신하는 네트워크 호출 작업처럼 시간이 오래 걸리는 작업들의 경우, 글로벌 큐 또는 다른 백그라운드 디스패치 큐에서 비동기적으로 구현하는 것이 좋다. 

 

Global Queue 

기본 설정은 Concurrent. 편의상 사용할 수 있게 만들어놓은 Concurrent Queue. 

The quality-of-service level to associate with the queue. This value determines the priority at which the system schedules tasks for execution. 

작업의 처리 우선순위를 설정할 있도록 QoS(Quality of Service) 파라미터가 제공된다.

완료 순서를 정할수는 없지만, 우선적으로 일을 처리하도록 할 수는 있다. 

 

iOS에서 Framework들은 모두 Background에서 구동이 된다.? 

 

Private(Custom) Queue

디폴트 설정은 Serial 이고 원하면 Concurrent 설정도 가능. Qos 설정도 가능.

레이블을 붙여 String으로 명명하여 설정 가능

 

4. QoS 우선순위

DispatchQoS

The quality of service, or the execution priority, to apply to tasks.

QOS 우선순위. 작업에 적용할 서비스 품질 또는 실행 우선순위

By specifying the quality of a task, you indicate its importance to your app. 

Because higher priority work is performed more quickly and with more resources than lower priority work, it typically requires more energy than lower priority work.

Accurately specifying appropriate QoS classes for the work your app performs ensures that your app is responsive and energy efficient.

QoS를 통해 작업의 우선순위를 설정하여, 앱에 해당 작업의 중요도를 알려줄 수 있다. 

우선 순위가 높을수록 더 빠르게 처리되는 대신, 그만큼 더 많은 리소스와 에너지가 쓰이게 된다. 따라서 QoS를 적절하게 사용해야 앱의 성능과 에너지 효율성을 최적화할 수 있다.  

 

.userInteractive : 거의 즉시

.userInitiated : 몇초. 

global() : 디폴트. 일반적인 작업

.utility

.background 

 

+ QoS 종류가 다른 글로벌 큐가 중첩되어 사용될 경우, 더 높은 우선순위를 가진 QoS를 따라 처리가 된다. 

 

5. GCD 사용 시 주의할 점

weak, strong 캡처 주의

다른 큐로 작업을 보내는 일은 클로저를 보내는 일. -> 객체에 대한 캡쳐 현상이 발생한다. 

클로저이기 때문에 작업을 보낼 때 reference counting 

대부분 weak self 사용해서 비동기 작업 처리해야..?

 

(비동기 작업에서) completion handler 존재 이유 

비동기 - 작업이 언제 끝나는 지 모름

task 끝난 시점 알아야 하니까, 비동기 작업이 명확하게 끝나는 시점 활용하기 위해. 

 

** RxSwift 를 사용한 비동기 처리의 이점

: 디스패치 큐 사용 시 비동기 작업의 결과를 completion handler 로 전달할 수 있다. 

Rx를 사용하면 비동기적으로 생기는 데이터를 completion 같은 클로저를 통해 전달하는 것이 아니라 리턴 값으로 편하게 전달할 수 있다. 

비동기로 나중에 생기는 데이터를 Observable로 감싸서 리턴하도록.

생성할 때는 create(), 값 전달할 때는 onNext() 사용해서 리턴하고, subscribe를 통해서 값을 사용.

 

 

 

 

 

 

 

 

 

 

 

참고 : velog-GCD에 대하여, 소들이 - GCD, https://velog.io/@leeyoungwoozz/TIL-2021.04.30-Fri

728x90
반응형