[Swift] (비)동기사랑 나라사랑, GCD

GUNDY·2023년 12월 18일
post-thumbnail

오늘의 주제는 동시성 프로그래밍과 Grand Central Dispatch(일명 GCD).

우선 동시성의 사전적 정의는 이러한데, 프로그래밍에서는 어떨까?

Concurrency is the notion of multiple things happening at the same time.

애플의 Concurrency Programming Guide 도입부분에서도 일반적으로 아는 동시의 개념으로 소개된다.

With the proliferation of multicore CPUs and the realization that the number of cores in each processor will only increase, software developers need new ways to take advantage of them.

멀티 코어 환경을 활용하는 방안 중 하나가 동시성 프로그래밍이라는 것.

Dispatch queues are an easy way to perform tasks asynchronously and concurrently in your application.

그리고 동시성 프로그래밍을 할 수 있는 방법 중의 하나가 GCD, 즉 DispatchQueue를 사용하는 것이다.

그런데 비동기랑 동시는 어떻게 다른데?

우선 동시성 프로그래밍과 헷갈릴 법한 개념은 병렬 프로그래밍이다.

  • 병렬: 여러 개의 CPU(코어, 물리적인 개념)가 한 작업을 분담해서 처리한다.
  • 동시성: 여러 개의 스레드(논리적인 개념)를 이용하여 동시에 여러 작업을 처리한다.

이 때 동시성 프로그래밍은 논리적으로는 싱글 코어 환경에서도 가능한다.

간단히 정리해보면 하나의 일을 여러 코어에서 하는 게 병렬, 여러 일을 하나(혹은 다수)의 코어에서 스레드를 분리하여 동시에 하는 게 동시성인 셈이다.

그런데 이 설명을 듣고 나면 멀티 코어와 관련된 것은 병렬 프로그래밍 같은데, 애플의 접근이 잘못된 것인가?

동시성 프로그래밍과 병렬 프로그래밍은 구분되는 개념이긴 하지만 서로 반대되는 개념은 아니기 때문에 이 둘이 동시에 일어날 수도 있다.

또 사실 애플이 정확하게 "멀티 코어 환경을 활용하는 방안 중 하나가 동시성 프로그래밍이다."라고 말한 것은 아니기 때문에 멀티 코어 환경을 활용하는 방안이라는 것은 비동기 프로그래밍을 의미하는 것일 수도 있다.

아무튼 이제 비동기가 뭔지도 알려줘

비동기는 동기와 함께 알아야 하는 개념이다.

  • 동기: 지정된 작업을 하나씩 순서대로 처리한다.
  • 비동기: 앞선 작업이 끝나기를 기다리지 않고 다음 작업도 시작한다.

이 때 비동기의 경우 각 작업이 언제 끝날지 알 수 없다. 앞선 작업이 끝나기를 기다리지 않기 때문에 알지 못한다.

동시성이랑 비동기는 어떻게 다른데?

동시성은 단순히 멀티 스레드를 활용하여 여러 일을 동시에 처리하는 것이고,

비동기는 스레드의 수와는 무관하게 앞선 작업의 끝을 기다리지 않는 것이다.

즉 둘은 동시에 일어날 수 있다.

아무튼 동시성 프로그래밍과 비동기 프로그래밍을 수행하는 쉬운 방법이 디스패치 큐라는 것이다.

In the past, introducing concurrency to an application required the creation of one or more additional threads. Unfortunately, writing threaded code is challenging.

멀티 스레딩을 활용한 프로그래밍 환경을 구축하려면 옛날에는 스레드를 직접 관리해줘야 했고, 이는 매우 어려웠다.

Rather than creating threads directly, applications need only define specific tasks and then let the system perform them.

스레드를 직접 생성하는 대신 작업만 지정해주면 시스템이 알아서 해준다는 것.

The advantage of dispatch queues is that they are simpler to use and much more efficient at executing those tasks than the corresponding threaded code.

스레드 코드보다 간단하고 효율적이다!

디스패치 큐

All dispatch queues are first-in, first-out data structures.

우선 큐라는 이름에서 알 수 있듯이 선입선출의 자료구조를 사용한다.

그렇기 때문에 이 디스패치 큐에 작업을 추가한 순서대로 각 작업들이 시작된다.

Serial

직렬 큐는 큐에 추가된 순서대로 한 번에 하나의 작업을 실행한다. 현재 실행 중인 작업은 디스패치 큐에 의해 관리되는 고유한 스레드(작업마다 다를 수 있음)에서 실행된다. 즉 앞서 설명한 동기 방식으로 큐 내부의 작업들을 처리한다.

Concurrent

동시 큐는 하나 이상의 작업을 동시에 실행한다. 작업은 대기열에 추가된 순서대로 시작된다. 현재 실행 중인 작업은 디스패치 큐에 의해 관리되는 개별 스레드에서 실행된다. 즉 앞서 설명한 비동기 방식으로 큐 내부의 작업들을 처리한다.

Main dispatch queue

메인 디스패치 큐는 애플리케이션의 메인 스레드에서 작업을 실행하는 전역적으로 사용 가능한 직렬 큐다. 이 큐는 애플리케이션의 런 루프(있는 경우)와 함께 작동하여 큐에 있는 작업의 실행과 런 루프에 연결된 다른 이벤트 소스의 실행을 인터리브한다. 애플리케이션의 메인 스레드에서 실행되기 때문에 메인 큐는 애플리케이션의 주요 동기화 지점으로 사용되는 경우가 많다.

iOS에서 UI와 관련된 작업을 할 때도 메인 스레드에서 처리해야하기 때문에 이 메인 디스패치 큐를 사용한다.

큐 관련 기술

디스패치 큐뿐만 아니라 GCD는 다양한 관련 기능을 제공한다.

Dispatch groups

디스패치 그룹은 완료를 위해 블록 객체 집합을 모니터링하는 방법이다. 필요에 따라 블록을 동기식 또는 비동기식으로 모니터링할 수 있다. 그룹은 다른 작업 완료에 따라 달라지는 코드에 유용한 동기화 메커니즘을 제공한다.

앞서 비동기 프로그래밍의 경우 작업들의 종료 시점을 알 수 없다고 했는데, 이 디스패치 그룹을 사용하면 그룹에 포함된 작업의 종료 시점을 기다릴 수 있다.

Dispatch semaphores

공유 자원에 접근할 수 있는 스레드의 수를 제어해주는 역할을 한다.

이 때 하나의 스레드만 접근할 수 있도록 설정한다면 멀티 스레드 환경에서 공유 자원에 대한 접근을 동시에 할 때 발생할 수 있는 문제들을 안전하게 처리할 수 있다.

Dispatch sources

디스패치 소스는 특정 유형의 시스템 이벤트에 대한 응답으로 알림을 생성한다. 이벤트가 발생하면 디스패치 소스는 처리를 위해 지정된 디스패치 큐에 비동기적으로 작업 코드를 제출한다.

마무리

오늘도 개념 탑재 완료!

코드에 대한 직접적인 부분이 더 궁금하다면 공식문서를 참고해보면 좋을 것 같다.

profile
개발자할건디?

0개의 댓글