티스토리 뷰

프로세스, 스레드, 동시성, 병렬성 등은 iOS 보다 더 low-level로 들어가 운영체제와 밀접한 관련이 있습니다.

그러나 이 글은 궁극적으로 GCD와 Operation Queue를 다루고 싶으니 iOS 개발 관점에 맞게 글을 풀어볼게요~

 

Concurrency

동시성은 여러 작업들을 동시에 실행할 수 있는 성질입니다.

엄밀히 말하면 싱글 코어에서 멀티 스레드를 동작시킬 수 있는 방식이니 동시에 실행되는 것 '처럼' 보이는 성질이죠.

멀티 코어 환경이 필요한 병렬성(Parallelism)과 자주 비교되는 개념이지만 이 글에서는 다루지 않을게요!

 

작업들은 스레드에서 실행이 됩니다. 아래 그림에 비유해보자면 차 = 작업, 차선 = 스레드 라고 볼 수 있겠네요.

보시다시피 버스전용차로는 뻥 뚫려있는 반면 일반 차선은 꽉꽉 막혀있습니다.

이렇듯 버스전용차로 = 메인 스레드, 일반 차선 = 백그라운드 스레드로 비유할 수 있습니다.

iOS에서 메인 스레드는 UI를 관장하고 있기 때문에 작업이 밀리거나 멈춰버리면 안되기 때문에 잘 관리할 필요가 있습니다.

 

관리의 필요성은 있으나 개발자가 일일이 관리하고 신경쓰는게 쉽지 않기 때문에 스레드의 생성과 관리를 GCD나 Operation Queue가 맡아서 하게 됩니다. 덕분에 개발자는 작업 queue들을 GCD에 넘겨주기만 하면 되죠. 그러나 GCD 또는 Operation Queue에 대해 알아보기 전에 queue에 대한 3가지 질문에 먼저 답을 하고 싶습니다.

 

1. Main thread와 Background thread의 차이

2. Serial queue vs Concurrent queue

3. Race condition이란?

1. Main thread / Background thread

Main thread는 한 개만 존재하고 나머지는 모두 background thread에 해당 됩니다. Main thread에서 가장 중요한 점은 UI와 관련된 코드는 모두 main thread에서 실행돼야 합니다. 혹여 UI 관련 코드를 메인 스레드에 작성하지 않았을 경우 main thread checker에 의해 보라색으로 경고를 해줍니다. 예를 들어 앱이 사진첩에 접근할 경우 UIImagePickerController를 열어야 합니다. 사진첩을 여는 과정을 아래와 같이 코드로 작성할 수 있습니다.

func presentPhotoLibrary() {
   mediaController.sourceType = .photoLibrary
   mediaController.allowsEditing = true
   mediaController.modalPresentationStyle = .fullScreen
   present(mediaController, animated: true)
}

 

당연히 메인 스레드에서 돌아가야 할 작업이지만 그렇지 않기 때문에 실행 후 런타임에 다음과 같은 문제가 생깁니다. 'Call must be made on main thread'. 왼쪽을 보시면 Thread 1 은 메인 스레드임을 알 수 있습니다. 문제는 Thread 10에서 생겼죠? Photos의 access callback을 처리하다 문제가 생겼나봅니다. 그래서 코드에 띄워 준 보라색 경고 창을 참고하여 수정을 해보면 다음과 같습니다.

 

func presentPhotoLibrary() {
   DispatchQueue.main.async { [weak self] in
      self.mediaController.sourceType = .photoLibrary
      self.mediaController.allowsEditing = true
      self.mediaController.modalPresentationStyle = .fullScreen
      self.present(self.mediaController, animated: true)
   }
}

 

위의 예시에서 Photos의 'access callback'에 문제가 생겼고, 이를 메인 스레드에서 돌아가게끔 수정을 하면서 문제를 해결했습니다. 여기서 백그라운드 스레드와 메인 스레드의 특징 중 하나를 살펴볼 수 있습니다. 바로 iOS의 Framework들은 모두 백그라운드 스레드에서 동작하다가 필요에 따라 메인 스레드를 delegate를 활용해 사용한다는 것이죠.

2. Serial Queue / Concurrent Queue

Queue는 FIFO(First-In First-Out, 선입선출) 특징을 갖는 자료구조 입니다. Task들이 들어 온 순서대로 실행됨은 변함이 없겠죠? 그렇다면 어떤 serial queue와 concurrent queue는 어떤 차이가 있을까요?

  Serial Queue Concurent Queue
공통점 Task 시작 순서 = Queue에 추가 된 순서
장점 종료 순서 예층 가능(= 실행 작업 순서) 동시에 여러개 실행 가능해서 빠름
단점 한 번에 하나만 실행할 수 있어서 느림 종료 순서 예측 불가능
(동시에 실행해서 누가 먼저 끝나는지 모름)

3. Race Condition (경쟁상태)

Serial queue는 특정 리소스 접근을 위해 사용되기도 하는데요 덕분에 경쟁 상태에 놓이는 상황을 방지할 수 있습니다. 운영체제의 관점에서 경쟁상태는 프로세스들이 공유 데이터에 서로 접근을 시도하는 상황을 뜻합니다. 이 때문에 상호배제, 교착 상태, 기아와 같은 문제가 발생하는데요 스레드도 같은 문제가 발생할 수 있겠죠?

 

출처

'iOS' 카테고리의 다른 글

[iOS] UICollectionView와 관련 된 경험들  (2) 2021.12.05
[iOS] URLSession dataTask의 Error (+ Result type)  (0) 2021.11.19
[iOS] Frame vs Bounds  (0) 2021.10.29
[iOS] URLSession 짚어보기  (0) 2021.10.27
[iOS] prepareForReuse란?  (0) 2021.10.19
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함