GCD 정리

김진수·2024년 1월 25일

GCD

간단하게 정리하면,
멀티코어 시스템에서 동시성 실행을 제공하는 프로그래밍 언어 요소, 런타임 라이브러리이다.

DispatchQueue

  • GCD로써 알려진 Dispatch는 GCD의 개념으로 동시성 프로그래밍을 지원하는 스위프트의 API이다.
  • FIFO(First in, First out)로 작업을 한다.
DispatchQueue.main.sync { }
DispatchQueue.main.async { }

DispatchQueue.global().async { }
DispatchQueue.global().async { }

하나씩 파헤쳐 보기전에,
main, global의 특징을 살펴볼때 보면 좋을거 같은 개념들을 간략하게 정리하였다.

Run Loop

  • 키보드 마우스같은 입력 소스에서 벌어지는 이벤트를 처리를 한다.

  • 특정 이벤트 발생시 스레드가 일해야 할땐 일하고 일이 없을땐 쉬도록 하는 애플에서 만든 스레드 관리 루프다.

  • current메서드를 사용시 쓰레드에 런루프가 존재하지않으면 생성후 리턴시키다는 것을 보면 아마 lazy의 특성을 가지고 있다고 생각한다.

  • 쓰레드내에서 런루프가 한 바퀴 도는 동안 2가지의 event Source를 수신한다.
    - Input Source: 다른 쓰레드나 어플리케이션으로부터 온 비동기 이벤트를 전달한다.
    - 타이머: 예약 된 시간 또는 반복 간격으로 발생하는 동기 이벤트를 전달한다.

  • 쓰레드에 들어온 이벤트 확인후, 결과 핸들러를 수행한다.
  • 런루프는 사용자가 반복문 등으로 runloop를 실행 시키지않는 이상 반복적으로 수행하지 않음 한 번 수행후 대기한다.

프로세서

  • 하드웨어 유닛(CPU)이다.
  • 한 컴퓨터가 여러개의 프로세서를 가진다면 멀티 프로세서, 두 개를 가진다면 듀얼 프로세서이다.

코어

  • 프로세서의 코어는 연산회로장치이다.
  • 하나의 연산창치를 가질때 싱클 코어, 두 개는 듀얼 코어, 여러개는 멀티 코어이다.

프로그램과 프로세스

  • 프로그램은 보조기억 장치에 저장된 실행코드이다.
  • 프로세스는 프로그램과 프로그램 상태가 메모리 상에서 작업하는 단위이다.
  • 동시에 여러개 프로세스를 운용하는 시분할 방식을 멀티태스킹이다.
  • 프로세스 관리는 운용체제가 한다.

스레드

  • 하나의 프로세스 내에세 실행되는 작업흐름의 단위이다.
  • 한 프로세스에 하나의 스레드가 있지만, 작업 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다.(멀티스레드)
  • 프로그램 처음실행이 될때 동작하는 것이 메인 스레드 그외에 생성된 것은 서브 스레드, 세컨더리 스레드이다.

Thread Safe란

멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없이 잘 작동되는 것을 의미한다.

이제 Main과 Global의 특징을 소개하겠다.

Main

  • Main에 작업 추가시 serial큐인 Main 스레드에서 처리한다.
  • 하나의 스레드에서만 작업을 처리하여 동시에 여러가지 일 처리 불가능하다.
  • 모든 앱에서의 작업은 스레드 위에서 처리되므로 하나 이상의 스레드가 필요하다.
  • 앱의 생명주기와 같은 생명주기를 가지고 있으며, 앱이 실행되면 늘 메모리에 올라와 있는 앱의 기본 스레드이다.
  • Main Thread중지시 앱도 중지한다.
  • 동시성 프로그래밍에서 여러 개의 스레드 사용시 (ex. DispatchQueue.global().sync / DispatchQueue.global().async) Main 스레드는 늘 존재하며 main 스레드에서 필요한 만큼 스레드가 파생되며 본인이 담당하는 작업이 끝나면 메모리에서 제거된다.
  • 전역적으로 사용 가능하다.
  • Global스레드들과 달리 run loop가 정해져있다.
  • Main 스레드는 자동으로 runLoop를 설정되고 실행이 되는 반면, Global은 사용자가 직접 current메서드를 실행시켜야된다.
  • UI 작업은 main 스레드에서만 작업 가능하며 애플에서 각각의 쓰레드에서 뷰의 변경사항들을 처리하고 정보를 읽는 과정이 비효율적이라고 생각하여 Uikit을 Thread Safe하게 설계하지않아 UI작업을 백 스레드에서 작업을 하면 안된다.

Global()

  • Main스레드에서 작업을 하지않고 Queue에 올라간 작업을 처리하기 위한 스레드이다.
  • 작업을 추가할때마다 새로운 스레드를 만들어 작업 처리 한다.
  • Main과는 다르게 런루프가 정해져있지 않다.
  • Global()이 호출될때만 메모리에 올라간 후 작업이 끝나면 메모리에서 제거된다.

동기 : 작업이 처리되기를 기다리는 것이다.

비동기 : 작업이 처리되기를 기다리지 않고 다른 스레드에서 처리되는 것이다.

직렬 : 큐가 작업 분배하기 귀찮아서 대기열에 있는 작업을 한 쓰레드로 몰아버는 것이다.

동시 : 큐가 대기열에 있는 작업을 여러 쓰레드에 골고루 분배하는 것이다.

DispatchQueue.main.sync


오류 이유 : 큐에서 메인에게 일을 시킬려고 하는데 메인이 일을 할 수도 있겠다 생각하고 계속 기다리는 문제가 생긴다. 그래서 사실상 main에 sync를 안쓴다.무한 대기 상태 즉, 교착 상태(DeadLock)이 발생할 수 있다.

DispatchQueue.main.async


Main 스레드는 비동기로 작업을 처리하여 dispatch에 넘겨 작업이 끝나기를 기다리지 않고 처리를 하였지만 단일 스레드에서만 작업이 이루어져 동시에 작업이 처리되지 않았다 그래서 쌓인 순서대로 작업이 처리되는 것이다.

DispatchQueue.global().sync


global().sync은 새로운 스레드를 생성하고 그 위에서 작업을 처리하는데 그 작업이 끝날때까지 기다리도록 동기적으로 작성을 하여서 위 같은 출력물이 나왔다. 그래서 작성된 순서대로 출력이 된다.
근데 작업시간이 DispatchQueu.main.sync과 동일하기 때문에 애플이 내부적으로 다른 쓰레드가 아니라 main쓰레드에서 작업을 시킨다.

DispatchQueue.global().async

Main 스레드와 다르게 다른 스레드를 불러서 비동기적으로 작업을 처리하여서 출력결과를 보면 뒤죽박죽으로 작업을 출력한 것을 볼 수 있다.
그래서 위처럼 동시에 작업을 처리하기 위해서는 여러개의 스레드(Global)가 필요하고 비동기로 작업을 처리해줘야한다.
처리하는 속도가 달라 어떤 코드가 먼저 출력될지는 예측할 수 없다.

profile
kimiosdev@gmail.com

0개의 댓글