Danny의 iOS 컨닝페이퍼
article thumbnail

동시성(Concurrency) 프로그래밍

만약 하나의 쓰레드에서 여러 작업(Task)을 실행하게 된다면 속도 및 성능 저하와 같은 문제가 발생하게 될 거예요.

 

간단한 예시로 Swift는 화면을 그릴 때(화면을 업데이트할 때) 메인 쓰레드에서 작업을 하게 됩니다. 

그러면 메인 쓰레드 쪽에 작업이 많이 쌓여 있다면 화면 업데이트하는데 문제가 생기겠죠?!

 

이것을 해결하기 위해 나온 게 동시성입니다. 다른 쓰레드로 뿌려줘서 메인 쓰레드의 일을 분산시켜 주는 거죠.

👉 선입선출(FIFO: First in, First out)로 동작

 

위의 그림과 같이 작업(Task)을 큐(Queue)로 보내주기만 하면 OS(운영체제)에서 자동으로 다른 쓰레드로 분산시켜 줍니다.

 

우리는 작업을 효율적으로 하기 위해선 어떤 큐(Queue)를 사용할지 고민만 하면 됩니다.

 

 

큐(Queue)의 종류

DispatchQueue(GCD - Grand Central DispatchQueue)

DispatchQueueGCD

대기열(Queue)보내는 방법입니다

 

크게 3가지로 나눌 수 있습니다.

main, global, custom

 

 

[Main Queue]

메인 쓰레드에서 동작하고 직렬(serial)로 동작

DispatchQueue.main

 

 

[Global Queue]

동시(Concurrent)적으로 동작

DispatchQueue.global()

QOS(Quality Of Service)작업우선순위를 부여가 가능 (6가지)

QOS 종류는 서비스품질이 높을수록(소요시간이 짧을수록) 여러 쓰레드를 사용합니다.

(참고, 우선순위가 낮다고 해서 작업을 완전히 미룬다는 것은 아니다. 중간중간 빈 쓰레드에서 작업함)

DispatchQueue.global(qos: .userInteractive)  // 소요 시간: 거의 즉시
DispatchQueue.global(qos: .userInitiated)    // 소요 시간: 몇초
DispatchQueue.global()                       // 기본값
DispatchQueue.global(qos: .utility)          // 소요 시간: 몇초에서 몇분
DispatchQueue.global(qos: .background)       // 소요 시간: 몇분 이상(에너지 효율)
DispatchQueue.global(qos: .unspecified)      // 오래된 API 지원

 

 

[Custom Queue]

기본값은 직렬(serial)로 동작하며

속성 attribute로 접근하여 동시(Concurrent)적으로도 동작 가능

또한, QOS를 통해 작업 우선순위도 지정도 가능합니다.

let queue = DispatchQueue(label: String,
                          qos: DispatchQoS,
                          attributes: DispatchQueue.Attributes)
let serialQueue = DispatchQueue(label: "Serial Queue")

// 동시큐
let concurrentQueue = DispatchQueue(label: "Concurrent Queue", attributes: .concurrent)

// 동시큐 + QOS 설정
let concurrentQueue = DispatchQueue(label: "Concurrent Queue",
                                    qos: .userInitiated,
                                    attributes: .concurrent)

 

 

OperationQueue

복잡한 연산(Operation)의 실행을 관리하고 대기열의 동작관리를 한다.

GCD기반으로 생성돼 있다.

사용이 불편하여 대부분 Dispatch Queue를 사용한다. 

let mainQueue =  OperationQueue.main  // 메인큐에서 작업
let queue = OperationQueue()          // 백그라운드큐에서 작업

 

 

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

동기(Sync)

동기는 시작한 작업이 끝나는 것을 기다린 후 다음 작업을 처리합니다.

 

메인 쓰레드에서는 Task1이 끝날 때까지 다음 작업을 막고 작업이 끝날 때 Task2를 수행합니다.

 

동시적으로 뿌려 주더라도 결국 메인 쓰레드에서는 순차적으로 작업을 진행합니다.

 

즉, 작업이 끝나기 전까지 메인 쓰레드에서는 다른 작업을 수행하지 못합니다

 

더보기
print("1")

DispatchQueue.global().sync {
    sleep(2)
    print("동기 작업")
}

print("2")

// 1 
// (2초 뒤에) 동기 작업
// 2

 

 

비동기(Async)

비동기는 시작한 작업이 끝나는 것을 기다리지 않고 바로 다음 작업을 처리합니다.

 

메인 쓰레드에서 Task1을 다른 쓰레드로 보내면 즉시 다음 작업인 Task2를 수행합니다.

 

각 작업은 오래 걸리거나 짧을 수 있기 때문에 결괏값이 나오는 대로 출력됩니다. 순서가 정해지지 않음 (완료된 순서대로)

 

즉, 비동기 작업은 메인 쓰레드에서 바로 다음 작업을 수행이 가능합니다.

 

그래서 비동기 작업은 네트워크 요청같이 작업시간이 오래 걸리는 작업을 하거나 뷰를 연속적으로 업데이트를 해야할 때 주로 사용됩니다.

 

더보기
print("1")

DispatchQueue.global().async { 
sleep(2)
print("비동기 작업중") 
}

print("2")

// 1
// 2
// (2초 뒤에) 비동기 작업중

 

 

직렬(Serial) 큐 와 동시(Concurrent)큐

직렬(Serial) 큐

메인 쓰레드에서 작업을 단 하나의 쓰레드로 보내서 작업을 처리하는 큐

 

작업의 순서가 필요한 경우 사용합니다.

 

 

동시(Concurrent) 큐

메인 쓰레드에서 작업들을 여러 개의 쓰레드로 보내서 작업을 처리하는 큐

 

각자 독립적이지만 유사한 여러 개의 작업처리할 경우 사용합니다.

 

 

참고

 

앨런 Swift문법 마스터 스쿨 (온라인 BootCamp - 2개월과정) - 인프런 | 강의

Swift문법을 제대로 이해, 활용해보고자 하는 철학을 바탕으로 과정이 설계되었습니다. 코딩에 대해 1도 모르는 비전공자를 시작으로 네카라쿠배에 입사할 수 있는 초고급 수준까지 올리는 것을

www.inflearn.com

 

 

 

 

 

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!