iOS/동시성 프로그래밍

GCD와 Operation, 동기와 비동기

소재훈 2022. 3. 30. 21:32

이 포스트는 인프런 Allen님의

iOS Concurrency(동시성) 프로그래밍, 동기 비동기 처리 그리고 GCD/Operation - 디스패치큐와 오퍼레이션큐의 이해

강의를 정리한 것입니다.

 

iOS Concurrency(동시성) 프로그래밍, 동기 비동기 처리 그리고 GCD/Operation - 디스패치큐와 오퍼레이션

동시성(Concurrency)프로그래밍 - iOS프로그래밍에서 필요한 동기, 비동기의 개념 및 그를 확장한 GCD 및 Operation에 관한 모든 내용을 다룹니다., - 강의 소개 | 인프런...

www.inflearn.com

 

지난시간에 우리가 해야할 일은 작업한 내용을 대기행렬(큐)로 보내는 것 뿐이고, 나머지는 iOS 운영체제에서 큐에 있는 작업을 알아서 다른 스레드에 분배해준다고 했었다. 이제는 좀더 자세하게, 대기행렬의 두 종류인 GCD와 Operation에 대해 간략한 정보를 알아보자. 

 

그리고 동기와 비동기에 대한 개념을 확실하게 정리해보자!!

 

iOS에는 두가지의 대기행렬, GCD와 Operation가 있다.
이 두 가지는 쓰레드를 직접 관리하지 않고 큐(Queue)라는 개념을 이용해서 작업을 분산처리 한다....ㅇㅅㅇ

한번 작업을 큐에 넣으면, iOS에서 GCD와 Operation의 개념을 사용해서 시스템에서 쓰레드의 숫자를 관리해주는 것이다.

따라서 지금 공부할 개념은 쓰레드보다 한단 계 높은 차원에서 일을 하는것이고, 네트워크와 관련된 작업 등 쓰레드에서 오래 걸리는 작업들이 비동기적으로 수행되도록 해준다.

 

다음 코드를 살펴보자.

DispatchQueue.global().async {
	// 비동기적으로 수행할 작업
}

DispatchQueue는 작업을 디스패치 큐로 보낼 것을,

global은 글로벌 큐

async는 클로저 안의 작업을 비동기적으로 수행한다는 것을 의미한다.

 

한마디로 다시 정리하면

글로벌 큐에 클로저 안에 오는 작업을 비동기적으로 보낼거야!

라는 의미이다.

 

윗부분처럼, DispatchQueue와 비동기 작업까지 한번에 작성할 수도 있고, 

아래와 같이 보낼 큐의 종류를 선언한 다음 비동기/동기 작업 클로저를 위치시킬 수도 있다.

let queue = DispatchQueue.global() // 보낼 큐의 종류를 선언
queue.async {
	// 비동기적으로 보낼 작업
}

 

또 하나 중요한 점이 있는데, async 클로저 블록안에 있는 작업은 하나의 묶음이기 때문에

순서대로 동작한다는 점이다.

 

이게무슨 말이냐...

DispatchQueue.global().async {
    task1()
    task2()
    task3()
}

위와 같은 코드가 있다고 할 때, async 클로저 내부의 작업은 하나의 작업 묶음이기 때문에

task1 -> task2 -> task3 순서로 동작한다는 의미이다...

아주 중요한 개념이니 기억해두도록 하자!!

 

🤔 GCD와 Operation의 차이

그렇다면 iOS의 대기행렬인 GCD와 Oepration에는 무슨차이가 있을까?

GCD

  • 클로저로 묶을 수 있는 간단한 작업을 처리할 때 사용
  • 함수를 사용하는 작업(메서드 위주)

Operation

  • GCD보다는 조금더 복잡한 일을 수행할 때 사용한다.
  • 데이터와 기능을 캡슐화한 객체
  • 취소/순서지정/일시중지(상태추적)등 여러 기능을 구현하고 싶을 때 사용한다.

Operation는 2016년에 발표되었고, 기본적으로 GCD를 기반으로 해서 처리한다.

GCD에서 비동기적으로 작업하면서 작업의 취소, 순서지정, 일시중지등 여러개념들이 필요해진것이 아닌가 생각해본다...

 

GCD와 Operation 둘 중 무엇을 써야한다고 정해져 있지는 않다!!

다만 Operation은

클래스로 만들어진 객체

이기때문에 한번 만들어 놓으면 재사용성이 좋다는 장점이 있다.


😑 동기(Synchronous)와 비동기(Asynchronous)...

먼저 비동기에 대해서 알아보자.

비동기는 1번쓰레드에서 다른 쓰레드에 작업을 대기열로 보내고, 대기열에서 알아서 다른 쓰레드에 보내게 되는데, 이때 보낸 작업이 완료되는 것을 기다리지 않고 바로 다음작업을 수행하는 것을 말한다. 

위 그림에서 스레드 1에서 대기열로 작업을 보내고, 대기열에서 작업을 스레드2로 할당해 주었는데, 

task1이 끝나기를 기다리지 않고, 1번 스레드는 그 다음 작업 task2를 수행한다는 것이다.

 

작업이 끝나기를 기다리지 않고, 바로 그 다음작업을 할 수 있기 때문에 

다시말하면 일을 시작시키고 기다리지 않기 때문에

메인쓰레드가 다른 일처리를 시작할 수 있다는 점에서 의미가 있다.

 

 

그 다음은 동기에 대해서 알아보자.

동기는 대기열로 보낸 작업이 다른쓰레드에서 끝날 때까지 기다린다.

따라서 쓰레드에서 다른 처리를 하지 못한다.

 

아래의 코드는

원래의 작업이 진행되고 있던 곳(메인 쓰레드)에서 디스패치 글로벌 큐로

모낸 작업을 동기적으로 기다리는 코드이다.

DispatchQueue.global().sync {

}
// 원래의 작업이 진행되고 있던 곳(메인스레드)
// 에서 디스패치 글로벌 큐로 보낸 작업을 동기적으로 기다린다.

작업을 시작시키고, 작업이 끝날 때까지 기다린다는 점이 중요하다.

 

하지만 작업을 다른 쓰레드로 보내고, 작업이 완료될 때까지 기다리는 것이 무슨 의미가 있을까?

그래서 사실은 동기보다는 비동기 작업을 많이 사용하고, 다른 쓰레드로 작업을 보내고

기다릴 바에야 원래의 쓰레드에서 처리하는 경우가 많다고 한다.

 

하지만 응용적으로 sync를 사용해야 하는 경우가 있다....이것은 나중에 알아보자.

 

동기와 비동기를 정리하면 다음과 같다!!

비동기(Async): 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 기다리지 않고 다음 작업을 진행.
동기(Sync): 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 기다렸다가 다음 작업을 진행

 

이러한 비동기 라는 개념이 일반적으로 필요한 이유는

대부분 서버와의 통신(네트워크의 작업) 때문이다 실제로 URLSession같은 네트워크와 관련된 작업들은

내부적으로 비동기적으로 구현되어 있다!!

네트워크에서 정보를 요청하면 작업이 얼마나 걸릴지 모르기 때문에

네트워크는 모두 비동기적으로 처리한다고 생각하면된다.