Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

동시성 프로그래밍 - 02 #13

Open
Brandnew-one opened this issue Jun 21, 2022 · 0 comments
Open

동시성 프로그래밍 - 02 #13

Brandnew-one opened this issue Jun 21, 2022 · 0 comments
Labels

Comments

@Brandnew-one
Copy link
Owner

Brandnew-one commented Jun 21, 2022

Concurrency

1편에 이어서 두번째 정리글이다!

사실 강의를 빠르게 다 듣고 정리하면서 복습하는 느낌으로 하려고 했는데 생각보다 강의 내용이 어려워서 정리하면서 복습하고 강의 내용을 이어서 들어야 할것 같다 😂

복습

오늘은 GCD의 종류와 특성, 그리고 사용할 때 주의사항에 대해 정리해보려고 하는데 그 전에 이전에 다뤘던 내용을 한번 정리 해보자

  • 작업들을 여러 쓰레드에 분산 시켜서 효율적으로 동작 시키기 위해서 동시성 프로그래밍을 이용한다
  • iOS에서는 쓰레드를 직접 관리하지 않고 GCD/Operation Queue에 넣어주면 OS가 알아서 쓰레드에 일을 분배한다
  • GCD/Operation Queue 에는 Serial queue, Concurrent queue 라는 특성이 있다
  • 동기와 비동기는 어떤 작업을 큐로 보낼 때 해당 작업의 완료를 기다리거나 바로 다음 작업을 시작하는 것을 의미한다
  • 직렬과 동시는 큐의 특성으로 직렬 큐의 경우 큐에 할당된 작업을 하나의 쓰레드에서 처리하도록 하고 동시큐는 큐에 할당된 작업을 여러 쓰레드에서 동시에 처리할 수 있도록 한다

GCD의 종류와 특성

GCD(=Dispatch Queue) 는 크게 3가지 종류로 나눌 수 있습니다.

  • 메인 큐
  • 글로벌 큐
  • 프라이빗 큐(커스텀)

메인큐

메인 큐는 오직 한 개만 존재하고, Serial 특성을 가지고, 메인큐에 할당된 작업들은 메인 쓰레드에서 동작한다!

우리가 동시성 프로그래밍을 고려하지않고 단순히 코드를 작성하면 메인 쓰레드에서 모든 작업을 처리한다고 했었다. 그럼 우리가 별도의 처리를 하지 않으면 작업들이 메인 큐에 할당된다는 것을 알 수 있다.

//DispatchQueue.main.sync {
  print("Hello")
//}

코드로 확인해보면 위와 같이 우리가 별도의 작업을 하지 않으면 DispatchQueue.main.sync가 감싸진 형태로 동작하는 것이다.
(물론 실제로 저렇게 코드를 작성하면 메인쓰레드가 쓰레드-세이프 하지 않기 때문에 오류가 발생한다!)

정리해보면 메인 쓰레드도 하나 메인큐도 하나 존재한다. 그러니까 메인큐는 필연적으로 Serial한 특성을 가질 수 밖에 없다. 왜? 여러 쓰레드에 동시 작업을 넣을 수가 없으니까!!

메인 쓰레드 이야기가 나온김에 메인 쓰레드의 중요한 특성에 대해서 하나 짚고 넘어가면 UI 관련 작업은 메인 쓰레드에서 동작한다
이는 iOS뿐만 아니라 모든 OS에서 동일하다. 왜 그럴까? 만약 화면전환 관련 로직이 여러 쓰레드에서 처리되어서 순서가 보장되지 않게 되면 우리가 의도하지 않은 동작이 일어날 수 있다!


글로벌 큐

글로벌 큐는 Concurrent 특성을 가지고, QoS(=Quality of Service)를 통해서 작업의 중요도를 결정 할 수 있다.

QoS에는 6가지 종류가 있다.

  • userInteractive
  • userInitiated
  • default
  • utility
  • background
  • unspecified
let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)

우선순위가 높은것 부터 차례대로 적으면 위와 같다. 우리가 QoS를 설정만 해주면 우선 순위가 높은 일에 더 많은 쓰레드를 알아서 배치 해준다.


프라이빗 큐(커스텀 큐)

커스텀 큐는 기본적으로는 Serial한 특성을 가지지만 Concurrent 로 설정할 수 있고 QoS 또한 설정 해줄 수 있다.

let customQueue = DispatchQueue(label: "bran")
let customConcurrentQueue = DispatchQueue(label: "bran", attributes: .concurrent)

코드로 확인해보면 위와 같다. QoS를 우리가 따로 설정해주지 않으면 OS가 알아서 추론해준다!

✋ 주의사항

1) 메인쓰레드에서 다른 큐로 작업을 보낼 때 sync를 사용하면 안된다

아까 메인 큐에 대해서 설명할 때 메인 쓰레드에서 UI 관련된 작업이 진행된다고 했었는데 메인 쓰레드에서 어떤 작업을 큐에 sync 로 보내면 어떻게 될까?

스크린샷 2022-06-21 오후 10 53 35

만약 Concurrent 특성을 가지는 큐에 task1, task2 를 sync 하게 보냈다고 가정해보자.

스크린샷 2022-06-21 오후 10 55 10

Concurrent한 특성을 가지는 큐이기 때문에 여러 쓰레드에서 작업들을 처리하게 될것이다. 하지만 sync하게 보냈기 때문에 UI를 담당하고 있는 메인 쓰레드는 다음 큐에 보낸 작업들이 완료되기 전까지 다음 작업을 이어서 진행할 수 없다!

스크린샷 2022-06-21 오후 10 59 11

큐로 보낸 작업들이 만약 시간이 오래 걸리는 작업이라면 그 시간동안 앱은 멈춰버리는 현상이 발생하고 짧더라도 우리가 피하고 싶던 앱이 버벅이는 현상이 나타나게 된다! 그래서 메인 쓰레드에서 큐에 작업을 보낼 때는 항상 비동기를 보내야 한다!

2) 현재와 같은 큐에 sync로 작업을 보내면 안된다

스크린샷 2022-06-21 오후 11 06 45

우선 위와 같이 Task1 안에 Task2가 포함되어 있는 작업이 있다고 가정해보자. 현재 Task1을 Concurrent 특성을 가지는 큐에 비동기적으로 보낸 상태이다. 근데 Task1에 포함된 Task2를 Concurrent 특성을 가지는 큐에 동기적으로 보내면 어떻게 될까?

DispatchQueue.global().async {
// Task 1
  DispatchQueue.global().sync {
  // Task2
  }
}

코드로 표현하면 이런 상황이다.

스크린샷 2022-06-21 오후 11 25 18

Task2를 Concurrent 특성을 가진 Queue에 sync 방식으로 넣어줬기 때문에 쓰레드1은 해당 작업이 완료 될 때까지 Block 상태가 된다.
Concurrent 특성을 가진 큐이기 때문에 큐는 들어온 Task2를 쓰레드1, 쓰레드2, 쓰레드3 어디든 넣어 줄 수 있고 우리가 여기에 개입할 수는 없다.

그런데 쓰레드1에서 Task2가 할당되면 어떻게 될까?
스크린샷 2022-06-21 오후 11 34 35

Task2가 완료되기 전에는 Task1을 실행할 수 없는데 Task2가 멈춰있는 쓰레드에 할당되었기 때문에 완료될 수가 없다.
이러한 상황을 교착상태(데드락)이라고 한다!

물론 큐에서 다른 쓰레드로 Task2를 할당하면 위와 같은 상황이 발생하지 않지만 그럴 가능성이 존재한다. 따라서 현재와 같은 큐에 sync 로 작업을 보내면 안된다!

그럼 어떻게 위와 같은 상황을 피할 수 있을까?
global 큐를 사용하는 경우, QoS다른 큐를 생성해서 사용하면 쓰레드가 겹치지 않는다고 한다!

위와 동일한 이유로 메인 쓰레드에서 DispatchQueue.main.sync 를 사용하면 안된다. 이해 되겠죠?

  • 메인 쓰레드에서 메인 큐로 작업을 보낸다 동기적으로
  • 메인 큐는 다시 메인 쓰레드로 작업을 보낸다
  • 하지만 동기적으로 메인 큐에 작업을 보냈기 때문에 메인 쓰레드는 block 상태이다

해당 내용은 앨런님의 강의를 듣고 이해한 내용을 정리한 글입니다!!

DispatchGroup 까지 강의를 들었는데 최대한 빨리 복습하고 정리하도록 하겠습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant