ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [GCD] DispatchQueue.. main큐와 gloabal큐? sync와 asnyc? 궁금증 해결해보자.
    앱등이에게 살충제를 뿌린다./Swift 2018. 9. 4. 16:22



    많은 언어에서 제공하는 비동기 처리 방식.

    Swift(또는 objc)에는 GCD가 있다.


    iOS개발을 하다보면, 아래 코드를 많이 보고, 또 사용할 수 밖에 없다.

    DispatchQueue.main.async {

    //...

    }


    구글에 GCD를 쳐보면 무수히 많은 정리문서가 존재한다. (심지어 한글로 포스팅한 글도 엄청 많음)

    그래서 난 나만의 정리를..위해서 포스트를 작성한다.




    아래 코드의 결과를 정확히 예측할 수 있다면, 학습이 되었다고 판단하겠다.

    UIViewController의 viewDidLoad()에서 작성한 코드니까, 아래 코드는 메인스레드에서 작동한다는 전제가 있다.



    GCD

    https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2

    Concurrency(동시성)

    iOS에는 여러 스레드가 존재한다. OS스케쥴러가 이 스레드들을 관리한다. 

    언제 어떤 스레드에서 작업을 할 것인지.. 이런것들 말이다. 


    코어가 1개인 싱글코어 하드웨어는 time-slicing이라는 기법을 통해 concurrency를 구현한다. 한 번에 1개의 스레드만 가동하기 때문에, 컨텍스트 스위치를 통해 이 스레드에서 저 스레드로 이동하며 작업을 수행한다. 

    하지만, 멀티코어 하드웨어는 동시에 여러개의 스레드를 수행할 수 있다. 따라서 time-slicing도 필요없고 컨텍스트 스위치도 필요가 없다. 이 것이 concurrency와의 차이점이고, 이 방식을 parallelism이라고 한다.

    GCD에는 여러 스레드 풀이 있고, GCD 추가한 작업을 어떤 스레드에서 수행할지는 GCD 결정한다.



    Queues

    GCD는 dispatch queues라는 큐를 관리한다. 

    클래스명은 DispatchQueue 


    GCD에 작업을 전달하면 GCD는 알맞은 큐를 선택하여 작업을 수행하도록 한다. 이 때, 작업 수행은 FIFO로 이루어진다.(First in First out) 

    Dispatch queues are thread-safe which means that you can access them from multiple threads simultaneously. The benefits of GCD are apparent when you understand how dispatch queues provide thread safety to parts of your own code. The key to this is to choose the right kind of dispatch queue and the right dispatching function to submit your work to the queue.


    큐는 Serial큐와 Concurrent큐가 있다. 


    Serial큐는 동시에 1개의 작업만을 수행한다. 작업을 언제 수행할 것인지는 GCD에서 컨트롤한다. 

    한 작업이 끝나고 다음작업을 시작하기까지 걸리는 시간을 우리는 알 수 없다. 


    Concurrent큐는 동시에 여러 작업을 할 수 있다. 큐에 추가된 순서대로 작업 수행을 시작한다. 동시에 여러작업을 수행하니, 작업이 끝나는 순서는 알 수 없다. 

    하나의 작업이 끝난 뒤, 다음 작업을 언제 수행하는지도 알 수 없다. 큐에서 현재 몇 개의 작업이 수행중인지도 알 수 없다. 

    This is by design: 그래서 이런 디테일에 의존하는 코드를 작성하면 안된다. 


    작업을 언제 수행할 지는 오롯이 GCD에서 관리한다. 예컨대, 새로 추가된 작업의 수행시간이 다른 작업 수행시간과 겹치게 된다면 GCD는 새로운 코어에 작업을 추가할 지, 컨텍스트 스위치를 통해 수행할지를 결정한다. 


    GCD에서 제공하는 큐의 타입은 아래와 같다. 

    - Main큐: 메인스레드에서 작동하는 큐. Serial큐. 

    - Global큐: 우선순위에 따라 4개가 존재함. (high, default, low, background) Concurrent큐 

    - Custom큐: 커스텀으로 만드는 큐. Serial일수도, Concurrent일 수도 있다. 하지만 여기에 추가된 작업은 결국 Global큐에서 수행한다.  (Requests in these queues actually end up in one of the global queues.) 


    Global큐의 우선순위는 QoS로 결정하는데, QoS도 마찬가지로 4가지가 있다. 순서대로 높은 우선순위 큐에 해당한다. 

    - User-interactive 

    - User-initiated 

    - Utility 

    - Background


    Synchronous vs. Asnychronous

    (sync와 async의 차이를 이해할 때, 많은 사람들이 혼동을 한다. 바로 Serial큐와 Concurrent큐의 개념과 헷갈리기 때문이다.) 

    GCD에서 Queue에 작업을 추가할 때, 동기 또는 비동기로 추가할 수 있다.

    Sync 

    DispatchQueue.sync(execute:)를 호출하여 사용한다. 

    sync 메소드를 호출한 caller는 전달된 작업이 끝날 때까지 기다린다. sync는 작업이 끝나야 return하기 때문이다. 

    ** 가끔 앱개발을 하다가 DispatchQueue.main.sync{}에서 크래쉬가 발생한적이 있지 않나요? 위와 같은 이유로 데드락이 발생했기 때문입니다. 

    Async 

    DispatchQueue.async(execute:)를 호출하여 사용한다. 

    sync와는 달리 작업을 전달하자마자 return한다. 

    즉, caller는 async를 호출한 뒤에, 다음작업을 바로 수행한다.



    그러면 위의 코드를 다시 보자



    "1" 무조건 1등으로 출력된다. 왜냐면 sync로 추가했기 때문에 1이 출력되기 전까지 다음문장으로 넘어가지 않는다.

    "2" 무조건 1다음으로 출력된다.

    "3" "2"가 출력된 뒤, 2초 뒤에 출력된다. (만약에 sync가 아닌 async였다면 "3"은 무조건!! 꼴지로 출력된다.)

    "4" 5와 6과의 관계는 알 수 없지만 확실한건 "7"보다는 늦게 출력된다. 왜냐하면 "4"를 메인스레드에 추가하기 전에 "7"을 출력하는 작업이 이미 추가되어 있고, 메인스레드는 Serial큐이기 때문이다.

    "5", "6" 서로 다른 Concurrent큐에 async로 추가되었다. 따라서, 출력되는 순서는 장담할 수 없다.

    "7" 3보다는 늦게 출력되고 4보다는 먼저 출력된다. 무조건!!



Designed by Tistory.