IAM iOS

[Swift] GCD, Dispatch Queue, 동기(Sync)/비동기(Async), 직렬(Serial), 동시(Concurrent) 본문

Swift

[Swift] GCD, Dispatch Queue, 동기(Sync)/비동기(Async), 직렬(Serial), 동시(Concurrent)

IAMiOS 2022. 3. 31. 17:06

 

GCD (Grand Central Dispatch)


동시성을 사용하면 장치에 여러 CPU 코어가 있다는 사실을 활용할 수 있다. 이러한 코어를 사용하려면 여러 스레드를 사용해야 하는데, 스레드는 저수준 도구로 효율적인 방식으로 스레드를 수동으로 관리하는 것은 매우 성가신 일이다.

  • GCD는 스레드 관리와 실행에 대한 책임애플리케이션 레벨 → 운영체제 레벨로 넘겨버리면서 멀티코어와 멀티 프로세싱 환경에서 최적화된 프로그래밍을 할 수 있도록 애플이 개발한 기술이다.
  • 각 애플리케이션에서 생성된 DispatchQueue를 읽는 멀티코어 실행엔진을 가지고 있는데, 이것이 Queue에 등록된 각 작업들을 꺼내서 스레드에 할당
  • 그렇기 때문에 개발자는 내부 동작을 자세히 알 필요 없이 Queue에 작업을 넘기기만 하면 돼서, Thread를 직접 생성하고 관리하는 것에 비해 관리도 용이하고 성능 면에서도 좋은 결과를 얻을 수 있음

 

 

Dispatch Queue


GCD의 개념으로 동시성 프로그래밍을 지원하는 Swift의 API가 Dispatch Queue인 것

  • 개발자가 해야 할 일은 Queue로 작업을 보내주기만 하면 된다.
  • Dispatch Queue는 작업의 실행을 관리
  • 대기열에서 제출된 각 아이템은 시스템에 의해서 관리된 스레드 풀에 의해 처리된다.

 

Main Queue

  • 모든 UI 처리는 메인 스레드에서 처리한다.
  • 메인 스레드에서 실행되는 Serial Queue
    • 메인 스레드는 오직 하나만 존재한다.
    • main queue는 메인 스레드로만 작업을 보내기 때문에 Serial(직렬)하게 동작하는 것

 

Global Queue

  • UI가 아닌 다른 작업들을 처리하는 큐
  • Concurrent(동시) 특성을 가진 Queue
  • Global Queue는 Main Queue보다 우선순위가 낮으며, Global Queue 내에서도 Qos에 따라서 우선순위가 정해진다.

 

Custom Dispatch Queue

  • 커스텀으로 만드는 것으로 Concurrent(동시성)과 Serial(직렬성) 아무거나 설정이 가능하며, Qos 도 가능하다.

 

Qos

  • Dispatch Queue에서 수행할 작업을 분류
  • 앱이 수행하는 작업에 적합한 Qos를 지정함으로써
    • 스케줄링, CPU 및 I/O 처리량 및 타이머 대기 시간과 같은 우선순위를 조정
    • 결과적으로 수행된 작업은 성능과 에너지 효율성 간의 균형을 유지

 

  1. .userInteractive : UI와 상호작용하는 작업, 빠르게 얻어야 하는 정보 일 때
  2. .userInitiated : UI 이벤트가 있을 때, 바로 일을 처리하도록
  3. .default : 일반적인 작업
  4. .utility : progress bar와 같이 함께 길게 실행되는 작업 (데이터 다운로드 등)
  5. .background : 제일 낮은 우선순위로 사용자가 인식하는 것과 상관없는 작업들에 대한 처리 (데이터베이스를 정리하는 등)
  6. .unspecified : QoS정보가 없음을 시스템에 신호

 

 

동기(Sync), 비동기(Async)


  • 메인 스레드 → Queue
  • 동기(Sync), 비동기(Async)는 메인 스레드에서 대기열을 어떤 방식으로 처리할지 결정하는 것
    • 작업을 보내는 시점에서 현재 스레드가 다른 작업을 처리할지 말지를 다루는 것

 

Sync : 스레드에서 보낸 작업을 큐에 추가한 후, 추가된 작업이 끝날 때까지 현재 스레드는 다른 작업을 하지 않고 기다린다.

Async : 큐에 작업을 추가하기만 할 뿐, 보낸 작업이 끝나는 것을 기다리지 않고 현재 스레드는 다른 작업을 시작한다.

 

 

직렬(Serial)큐, 동시(Concurrent)큐


  • Queue → Thread
  • 동기(Sync), 비동기(Async)로 보낸 작업들을 어떤 대기열을 사용할지 결정하는 것
    • 순차적으로 처리할지(Serial), 동시에 처리할지(Concurrent) 결정
  • 큐는 FIFO(First In First Out) 형태로 먼저 들어간 것이 먼저 나오는 특징
    • 직렬(Serial)큐, 동시(Concurrent)큐로 보내면 항상 그 작업은 맨 뒤로 보내짐

 

Serial

  • 이전 작업이 끝나면 다음 작업을 순차적으로 실행하는 직렬 형태의 Queue
    • 하나의 스레드로만 작업을 보냄
  • 작업의 순서가 우리가 큐에 넣은 순서이기 때문에 선후관계가 명확히 해야 하는 경우에 사용
    • task의 시작과 종료에 대한 순서를 알 수 있다.

 

Concurrent

  • 병렬 형태로 실행되는 Queue
    • 여러 개의 다른 스레드로 작업을 보내기 때문에, 여러 작업을 동시에 할 수 있는 방식
  • 작업은 순서와 관련 없이 완료될 수 있다.
    • 예를 들어 하나의 일이 나머지 2개의 일보다 더 가벼운 일이라면 가장 마지막에 들어왔음에도 불구하고 먼저 끝날 수 있는 것
    • 그렇기에 해당 일들에 대한 순서를 알 수가 없다.
    • 무조건 Concurrent 한 방식이 좋지 않을 수 있다는 것

 

 

Case


  • SerialQueue.Sync

메인 스레드에서 큐로 넘어간 작업이 끝나야 메인 스레드에서 다른 작업을 할 수 있고, 큐에 들어간 작업은 하나의 스레드에서 순차적으로 실행되며, 이 일이 다 끝나야 해당 코드 블락이 끝나서 다음 일을 메인 스레드에서 진행한다.

  • SerialQueue.Async

메인 스레드에서 큐로 작업이 넘어가자마자 메인 스레드는 다른 일을 처리할 수 있는 것이다.
하지만 큐에 들어간 작업은 하나의 스레드에서 순차적으로 진행되어야 한다.

  • ConcurrentQueue.Sync

메인 스레드에서 작업을 큐로 넘길 때, 해당 작업이 안 끝났으면 끝날 때까지 기다린다. 이걸 기다려야 하기 때문에 메인 스레드가 멈출 것이다. 큐에 들어간 작업은 여러 개의 스레드로 분배되어 처리되고, 이 일들이 다 끝나야 해당 코드 블락이 종료되는 것

  • ConcurrentQueue.Async

메인 스레드에서 작업을 큐로 넘기자마자 반환되고, 작업이 언제 끝날지 모르는 상태에서 이미 메인 스레드에서의 일은 끝난 것이다. 그리고 큐에 들어간 일들이 Concurrent 하게 여러 개의 스레드로 분배되어 일이 처리되어 언제 끝날지 모르는 상태에서 이미 해당 코드 블락은 끝인 것이다.

 

 

참고

 

'Swift' 카테고리의 다른 글

[Swift] NSCache, 이미지 캐시  (0) 2022.03.27