본문 바로가기

Swift

[Swift] 시디의 GCD - 1편

안녕하세요 여러분! 드디어 티스토리 첫 포스트 입니다..!

iOS 공부를 시작하고 처음 쓰는 블로그라 설레네요ㅎㅎ

 

???: 시디는 뭐고 GCD는 또 뭐냐?

 

포스팅 제목부터 이런 의문이 드시는 분들이 계실 것 같습니다.

시디는 접니다ㅋ

 

???: 시디는 너고 그럼 GCD는 뭐냐?

 

GCD는 Grand Central Dispatch의 약자로 애플에서 제공하는 비동기 프로그래밍 프레임워크입니다.

이 녀석이 어떤 녀석인지는 지금부터 알아보도록 하시죠!

 

그래서 시디의 GCD가 뭐냐 시디가 공부해본 GCD라는 뜻입니다.

(사실 이 제목으로 블로그 쓰고 싶어서 GCD 공부함ㅋ_ㅋ)

 

아무튼 시디의 GCD 바로 시작 하겠습니다.

 

GCD(Dispatch)

먼저 애플 공식 문서를 살펴보겠습니다.(GCD는 Dispatch 프레임워크와 같은 말)

https://developer.apple.com/documentation/DISPATCH

"시스템에서 관리하는 디스패치 큐에 작업을 제출하여 멀티코어 하드웨어에서 코드를 동시에 실행"

 

저는 여기서 디스패치 큐와 코드를 동시에 실행한다는 부분이 눈에 들어왔고 이것이 GCD를 이해하는데 가장 중요한 부분이라고 생각했습니다.

그래서 이번에는 디스패치큐와 코드의 동시 실행이라는 내용을 중심으로 알아 보겠습니다!

 

근데 코드가 동시에 실행되는 것을 왜 알아야 하지?

먼저 코드가 동시에 실행된다는 것을 이해하기 위해 동기 / 비동기 라는 용어부터 알아 보겠습니다.

동기(Synchronous)

동기는 작업이 끝날 때 까지 기다리는 것 입니다. 1번 작업이 끝나고 2번이 실행되는 방식으로 1번 코드의 실행이 끝이 난후 2번 코드가 실행되고 3번, 4번도 이런식으로 실행됩니다. 

비동기(Asynchronous)

비동기는 작업이 끝나는 것을 기다리지 않고 다음 작업이 실행되는 것입니다. 1번 코드의 실행이 끝나기 전에 2번, 3번, 4번의 코드가 동시에 실행됩니다.

 

우리가 개발할 때 코드가 동시에 실행되어야하는 상황들이 존재합니다. 

  • 서버에서 데이터를 받아오는 작업
  • 파일을 읽는 작업
  • 백그라운드 실행, 로딩 창 등의 작업

특히 iOS를 개발하는 입장에서 비동기 처리는 앱의 사용성과 관련이 될 수 있기 때문에 필수 개념이라고 생각합니다.

예를 들어 UI작업과 서버통신이 동기로 작업이 될 경우 사용자는 서버통신을 하는 동안 앱에서 아무런 동작을 할 수 없게 됩니다.

이런 경우 사용자는 답답함을 느끼게 되고 이 앱은 사용성이 좋지 않은 앱이 될 것입니다.

우리는 이 문제를 UI작업과 서버통신을 비동기로 처리해 해결할 수 있습니다. 사용자가 앱을 동작시키는 동안 UI작업과 서버통신이 비동기로 이루어진다면 사용자는 서버통신 중에도 앱을 끊김 없이 사용할 수 있을 것입니다.

 

DispatchQueue

먼저 애플 공식 문서를 살펴보겠습니다.

https://developer.apple.com/documentation/dispatch/dispatchqueue

"앱의 메인 스레드 또는 백그라운드 스레드에서 작업의 직렬 또는 병렬 실행을 관리하는 객체"
  • 디스패치 큐는 블록 객체 형태의 작업을 제출할 수 있는 FIFO 큐
  • 디스패치 큐는 작업을 직렬 혹은 동시에 실행
  • 디스패치 큐에 제출된 작업은 시스템에서 관리되는 쓰레드 풀에서 실행
  • 앱의 메인 스레드를 나타내는 디스패치 큐를 제외하고 시스템은 작업을 실행하는 데 어떤 스레드를 사용하는지 보장하지 않음

디스패치큐에 작업을 동기 혹은 비동기로 제출합니다. 작업을 동기로 제출 했을 때, 코드는 작업 실행이 끝날 때까지 기다립니다. 작업을 비동기로 제출했을 때, 코드는 실행을 지속하면서 작업은 다른 곳에서 실행됩니다.

 

스레드(Thread)

먼저 설명을 보면 스레드라는 단어가 반복적으로 등장하고 있습니다. 이 용어 부터 살펴 보겠습니다.

스레드는 하드웨어 스레드와 소프트웨어 스레드가 있습니다. 하드웨어 스레드는 CPU의 코어가 동시에 할 수 있는 작업의 갯수를 의미합니다. 소프트웨어 스레드는 프로세스 내의 작업 단위를 의미합니다. 제가 이번 포스팅에서 사용하는 스레드는 소프트웨어 스레드라고 생각해주시면 됩니다.

 

직렬(Serial) / 병렬(Concurret)

직렬, 병렬이라는 단어도 반복적으로 보이고 있습니다. 직렬은 한개의 스레드에서 처리하는 방식이고 병렬은 여러 개의 스레드에서 처리하는 방식 입니다.

 

Dispatch Queue 사용

DispatchQueue.큐종류.동기/비동기 {
	// 작업
}

Dispatch Queue는 위와 같은 코드를 작성해 사용할 수 있습니다.

 

큐의 종류로는 main과 global, custom이 있습니다.

  • main: 현재 프로세스 메인 스레드의 작업을 보관하고 실행하는 큐입니다. 메인 큐에서만 동작하기 때문에 Serial이라는 특성이 있습니다.
  • global: 메인 스레드가 아닌 다른 스레드의 작업을 보관하고 실행하는 큐입니다. 여러 스레드로 작업이 분산되어 처리되는 Concurrent라는 특성이 있습니다. qos(quality-of-service)를 통해 작업의 우선순위를 부여할 수 있습니다.
  • custom: 개발자가 원하는 특성(직렬/병렬 등)으로 큐를 생성할 수 있습니다.

직렬/병렬 + 동기/비동기

동기/비동기는 큐에 작업을 제출하는 주체(메인 스레드)가 기다리는 기다리지 않는 지에 대한 설정입니다.

직렬/병렬은 큐에 제출된 작업이 어떤 스레드에서 처리되는지에 대한 설정입니다.

설정별 조합을 알아 보겠습니다.

 

let serialQueue = DispatchQueue(label: "Serial")
serialQueue.sync {
    print("Serial + Sync")
}
  • 직렬 + 동기: 메인 스레드가 작업을 큐로 보내고, 큐는 기존에 작업이 실행되던 큐와 같은 스레드로 작업을 보냅니다. 그리고 메인 스레드는 해당 스레드의 모든 작업이 모두 처리(직렬)될 때까지 기다립니다(동기).
  • 메인 + 동기(DispatchQueue.main.sync): 직렬로 동작하는 Main Dispatch Queue의 경우 동기로 작업을 제출하면 문제가 발생합니다. 메인 스레드는 작업을 제출하고 기다리게 되는데, 큐는 메인 스레드로 작업을 보내게 됩니다. 이렇게 되면 기다리고 있는 메인 스레드에 작업이 할당되어 이 작업은 영원히 실행되지 않게되는 교착 상태가 발생합니다.

 

serialQueue.async {
    print("Serial + Async")
}
  • 직렬 + 비동기: 메인 스레드는 작업을 큐로 보내고 기다리지 않습니다(비동기). 큐는 기존에 작업이 실행되던 큐와 같은 스레드로 작업을 보냅니다. 해당 스레드의 이전 작업이 모두 처리되고 나서 작업이 실행됩니다(직렬).

 

DispatchQueue.global().sync {
    print("Concurrent + Sync")
}
  • 병렬 + 동기: 메인 스레드는 작업을 큐로 보냅니다. 큐는 작업을 여러 스레드로 분산해 보냅니다. 메인 스레드는 여러 스레드가 작업을 처리(병렬)할 때 까지 기다립니다(동기).

 

DispatchQueue.global().async {
    print("Concurrent + Async")
}
  • 병렬 + 비동기: 메인 스레드는 작업을 큐로 보내고 기다리지 않습니다(비동기). 큐는 작업을 여러 스레드로 분산해 보냅니다. 여러 스레드가 작업을 처리(병렬)합니다.

 

지금까지 동기/비동기와 Dispatch Queue에 대해 알아 보았습니다. 2편에서는 좀 더 자세한 활용 방법에 대해 알아보도록 하겠습니다!

시디의 GCD는 계속된다..!

 

 

[참고 자료]

https://developer.apple.com/documentation/DISPATCH

https://jeonyeohun.tistory.com/279

https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-4-a621eca0a1d2