ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS/Swift] 동시성 프로그래밍
    야매 iOS 2023. 8. 6. 17:53

    CPU의 스레드와 iOS 내부의 스레드

    스레드라는 동일한 단어를 사용하므로 조금 헷갈릴 수 있으나 CPU의 스레드와 iOS 내부에서 말하는 스레드는 다르다.

    CPU의 스레드

    CPU의 스레드에 대해서 알기 위해선 먼저 코어라는 개념을 알아야 한다.

    코어

    CPU에서 독립적으로 일하는 주체

    싱글코어

    CPU 내부에 하나의 코어

    멀티코어

    CPU 내부에 여러 코어

    싱글코어의 한계(기술적인 한계)로 인해 멀티코어로의 전환이 이뤄지고 있다.

    • 싱글코어의 기술력을 높이는 것보다 코어 간의 통신에 집중한다.

    스레드

    CPU의 스레드는 CPU 제조사의 기술이다.

    • 물리 코어에 여러 스레드로 용도를 나누는 기술

    → 실제 물리적으로 2개의 코어가 있는 것처럼 동작하고 OS는 실제로 2개의 코어가 있다고 착각한다.

    iOS 내부의 스레드

    소프트웨어 측면의 스레드

    💡 CPU의 스레드와 소프트웨어 측면의 스레드는 다른 개념이라는 것을 알 수 있다. 그렇기 때문에 CPU의 스레드 수는 정해져 있지만 프로그램에선 스레드를 개발자가 원하는만큼 만들어 낼 수 있는 것이다.


    동시성 프로그래밍이란?

    • 작업을 다른 스레드로 분산시키는 것
    • 작업을 다른 스레드에서 일하게 하는 것

    iOS 동시성 프로그래밍

    iOS는 작업을 대기열 (queue)에 보내면 시스템에서 알아서 스레드로 분산처리 한다.

    시스템이 스레드 숫자를 관리한다.

    • 시스템에 대한 지식 없이 직접 스레드를 생성하는 것은 하드웨어의 부하를 일으켜 앱의 성능이 저하될 수 있기 때문

    Queue 종류

    GCD (Grand Central Dispatch)

    • 간단한 일
    • 클로저로 작업을 받는다.
    • FIFO
      • 먼저 들어온 task가 먼저 처리된다.

    Operation Queue

    • 복잡한 일
    • 작업은 Operation(property와 메서드를 캡슐화한 객체) 단위
      • 클래스임으로 재사용 용이

    Opeartion Queue는 GCD 기반

    GCD에서 여러 일을 처리하면서 여러 기능이 필요해지면서 OperationQueue가 탄생했다.

    • 취소, 순서지정, 일시중지(상태추적)

    GCD에서 애매하게 취소와 순서지정 기능을 제공하긴 한다

    💡 프로젝트의 효율성 또는 사례 적합성을 통해 양자택일 하면 된다.


    동기(Sync)와 비동기(Async)

    스레드와 관련된 특징

    이 강의에서 동기의 개념은 (동기 + blocking), 비동기의 개념은 (비동기 + nonBlocking)

    • Queue에서 작업을 할당할 때 sync 또는 async 메서드르 사용하는데 그에 따라 구분한 것 같다.

    Sync

    현재 스레드에서 작업 큐로 task를 할당한 후 task가 끝날 때까지 스레드가 대기하는 형태

    DispatchQueue.global().sync {
    		// task
    }
    

    위의 에시에서 스레드는 default 우선순위를 가지는 큐로 task를 동기적으로 할당했다.

    • 할당한 task가 모두 처리되기 전까지 현재 스레드는 블로킹된다. (다른 작업을 진행할 수 없다)

    하지만 동기적으로 처리할 것인데 큐를 생성하고 큐에 task를 할당해 다른 스레드에서 처리할 필요가 있나?

    • 그러므로 동기처리를 하면 실질적으로 현재 스레드에서 진행한다.
    // 현재 메인 스레드
    
    let queue = DispatchQueue.global()
    
    queue.sync {
    		print(Thread.isMainThread)
    		sleep(10)
    		print("queue finished")
    }
    print("this is main thread")
    print(Thread.isMainThread)
    
    /* output
    true
    queue finished
    this is main thread
    true
    */
    

    위의 예시에선 글로벌 큐에 task를 할당했지만 실제로 메인 스레드에서 task가 진행되는 것을 알 수 있다.

    Async

    현재 스레드에서 작업 큐로 task를 할당한 후 작업이 끝날 때까지 기다리지 않는다.

    DispatchQueue.global().async {
    		// task
    }
    

    위의 에시에서 스레드는 default 우선순위를 가지는 큐로 task를 비동기적으로 할당했다.

    • 스레드는 task를 큐에 할당한 후 task가 끝날때까지 대기하지 않고 다른 일을 진행한다.

    직렬(Serial) & 동시(Concurrency)

    큐의 특징

    Serial

    큐가 한 개의 스레드로 작업을 보내는 것

    → 순서가 중요한 작업을 처리할 때 사용

    Concurrency

    큐가 여러 스레드를 사용해서 작업을 보내는 것

    • 몇 개의 스레드로 분산할지는 시스템이 알아서 결정하지만 여러 스레드로 분산 처리한다.

    → 각자 독립적이지만 유사한 여러 개의 작업할 때 사용

    → ex/ 셀에 있는 이미지를 불러오는 것은 독립적이지만 유사한 작업


    스레드와 큐의 블로킹

    스레드가 블로킹되는 것과 큐가 블로킹 되는 것은 별개의 개념이지만 계속 헷갈려서 정리

    스레드 블로킹

    스레드의 블로킹 여부는 async 또는 sync의 여부에 따라 달라진다.

    Async

    스레드가 큐에 작업을 던지고 다시 돌아와서 다른 작업 처리

    Sync

    스레드가 큐에 전달한 작업이 완료될 때까지 다른 작업을 진행하지 않는다.

    큐의 블로킹

    큐의 블로킹 여부는 serial 또는 concurrent 여부에 따라 달라진다. 큐는 FIFO의 특징을 갖는다는 것을 기억하는 것이 가장 중요하다.

    Serial

    하나의 스레드만 사용하므로 현재 진행중인 task가 완료되지 않는다면 해당 스레드에 다른 task를 할당할 수 없다.

    → 그러므로 큐가 블로킹 된다.

    Concurrent

    여러 스레드를 사용할 수 있기 때문에 task가 완료되지 않아도 다른 스레드에 task를 할당할 수 있다.

    • 스레드 생성을 시스템이 담당하고 있으므로 스레드 수에 따라 블로킹이 될 수도 있다.

    조합

    iOS의 동시성 프로그래밍은 **작업을 할당하는 방식(sync, async)**와 큐에서 **작업을 처리하는 방식(serial, concurrent)**의 조합으로 진행된다.

    어떤 조합을 사용하느냐에 따라 아래와 같은 특징을 가질 수 있다.

    • 스레드 블로킹 & 큐 논블로킹
    • 스레드 블로킹 & 큐 블로킹
    • 스레드 논블로킹 & 큐 논블로킹
    • 스레드 논블로킹 & 큐 블로킹

    스레드의 블로킹 상태와 큐의 블로킹 상태는 공유되지 않는다는 것을 알면 이해하기 좀 더 쉬울 거 같다

    • 스레드 블로킹 & 큐 논블로킹

    주의해야 할 점

    // main thread
    
    DispatchQueue.main.sync {
    
    }
    

    위와 같은 코드를 작성하면 Xcode에서 에러를 뱉는다.

    에러를 뱉는 이유는 위 코드는 데드락 상태에 걸리기 때문이다.

    1. 메인 스레드에서 메인 큐로 작업을 동기적으로 보냄
    2. 메인 스레드는 동기적으로 작업을 보냈으므로 블로킹
    3. 메인 큐는 메인 스레드에서 보낸 작업을 스레드에 보내 처리하고 싶으나 현재 메인 스레드가 블로킹되어 있으므로 작업을 처리하지 못함

    메인 스레드는 작업이 처리되기 대기하고 있고 메인 큐는 작업을 스레드에 할당하기 위해 기다리면서 결국에 아무런 작업도 진행하지 못하게 된다.

     

    강의
    https://www.inflearn.com/course/iOS-Concurrency-GCD-Operation

Designed by Tistory.