iOS/Swift

[Swift] GCD(Grand Central Dispatch)에 λŒ€ν•΄μ„œ

κ²½ν‘Έ 2023. 3. 1. 18:00
λ°˜μ‘ν˜•

μ•ˆλ…•ν•˜μ„Έμš”~ 

 

μ˜€λŠ˜μ€ GCD에 λŒ€ν•΄μ„œ μ •λ¦¬ν•˜λ €κ³  ν•©λ‹ˆλ‹€.

GCD의 κ°œλ…κ³Ό μ‚¬μš©λ²•, 그리고 μ˜ˆμ‹œλ₯Ό μ€‘μ‹¬μœΌλ‘œ 정리해 λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

 


 

 

GCD의 κ°œλ…

- GCD (Grand Central Dispatch)λŠ” C기반의 μ €μˆ˜μ€€ API둜 Apple의 닀쀑 μŠ€λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ„ μœ„ν•œ κΈ°μˆ μž…λ‹ˆλ‹€.

 

 

GCDλŠ” λΉ„λ™κΈ°μ μœΌλ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλŠ” 큐(Queue)λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

이 νλŠ” λ°”λ‘œ 저희가 μ•Œκ³  μžˆλŠ” DispatchQueueμž…λ‹ˆλ‹€.

 

이 νλŠ” 각각의 μž‘μ—…μ€ λ³„λ„μ˜ μŠ€λ ˆλ“œμ—μ„œ μˆ˜ν–‰λ˜λ©° μ•„λž˜μ™€ 같이 두 가지 μ’…λ₯˜λ‘œ λ‚˜λ‰©λ‹ˆλ‹€.

 

(1) Serial Queue

 

- 큐에 μΆ”κ°€λœ μž‘μ—…μ€ ν•œ λ²ˆμ— ν•˜λ‚˜μ”© 순차적으둜 μ‹€ν–‰λ©λ‹ˆλ‹€. λ‹€μŒ μž‘μ—…μ€ 이전 μž‘μ—…μ΄ λλ‚˜μ•Ό μ‹€ν–‰λ©λ‹ˆλ‹€.

- main queue : UI μ—…λ°μ΄νŠΈμ™€ 같은 메인 μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰ν•΄μ•Ό ν•˜λŠ” μž‘μ—…μ— μ‚¬μš©λ©λ‹ˆλ‹€. 이 큐에 μž‘μ—…μ„ μΆ”κ°€ν•˜λ©΄, ν•΄λ‹Ή μž‘μ—…μ€ 메인 μŠ€λ ˆλ“œμ—μ„œ 순차적으둜 μ‹€ν–‰λ©λ‹ˆλ‹€.

 

(2) Concurrent Queue

 

- 큐에 μΆ”κ°€λœ μž‘μ—…μ€ λ™μ‹œμ— λ³‘λ ¬μ μœΌλ‘œ μ‹€ν–‰λ©λ‹ˆλ‹€. 이전 μž‘μ—…μ΄ μ™„λ£Œλ˜μ§€ μ•Šμ•„λ„ λ‹€μŒ μž‘μ—…μ΄ 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€.

- global queue : λ³‘λ ¬μ μœΌλ‘œ μž‘μ—…μ„ μ‹€ν–‰ν•˜κΈ° μœ„ν•œ νμž…λ‹ˆλ‹€. 이 큐에 μž‘μ—…μ„ μΆ”κ°€ν•˜λ©΄, μ‹œμŠ€ν…œμ΄ μ‚¬μš© κ°€λŠ₯ν•œ λͺ¨λ“  μžμ›μ„ ν™œμš©ν•˜μ—¬ μž‘μ—…μ„ λ™μ‹œμ— μ²˜λ¦¬ν•©λ‹ˆλ‹€.

 

GCD의 μ‚¬μš©λ²•

GCDλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ μ•žμ„œ μ„€λͺ…ν–ˆλ˜ 큐인 DispatchQueueλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

그리고 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œλ₯Ό λΈ”λ‘μœΌλ‘œ μž‘μ„±ν•˜μ—¬ 큐에 μΆ”κ°€ν•©λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄, Serial Queueλ₯Ό μƒμ„±ν•˜κ³  μž‘μ—…μ„ μΆ”κ°€ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

let serialQueue = DispatchQueue(label: "example")
serialQueue.async { 
   // μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œ 
}

// μœ„ μ½”λ“œμ—μ„œλŠ” label을 μ‚¬μš©ν•˜μ—¬ 큐λ₯Ό μƒμ„±ν•˜κ³ , async λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μž‘μ—…μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.
// async λ©”μ„œλ“œλŠ” μž‘μ—…μ„ λΉ„λ™κΈ°μ μœΌλ‘œ μˆ˜ν–‰ν•˜λ©°, μž‘μ—…μ΄ λλ‚˜λ©΄ νμ—μ„œ μžλ™μœΌλ‘œ μ œκ±°λ©λ‹ˆλ‹€.

// label이 μ•„λ‹Œ GCDμ—μ„œ 기본적으둜 μ œκ³΅ν•˜λŠ” main queueλ₯Ό μ΄μš©ν•˜λ©΄ λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

DispatchQueue.main.async {
    // UI μ—…λ°μ΄νŠΈ λ“±μ˜ μž‘μ—…
}

 

 

Concurrent Queueλ₯Ό μƒμ„±ν•˜κ³  μž‘μ—…μ„ μΆ”κ°€ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

let concurrentQueue = DispatchQueue(label: "example", attributes: .concurrent)
concurrentQueue.async {
   // μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œ 
}

// μœ„ μ½”λ“œμ—μ„œλŠ” attributes 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ Concurrent Queueλ₯Ό μƒμ„±ν•˜κ³ 
// async λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μž‘μ—…μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.

// λ§ˆμ°¬κ°€μ§€λ‘œ labelκ³Ό attributesκ°€ μ•„λ‹Œ global queueλ₯Ό μ‚¬μš©ν•˜λ©΄ λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

DispatchQueue.global(qos: .background).async {
   // λ°±κ·ΈλΌμš΄λ“œ μž‘μ—… λ“±μ˜ μž‘μ—…
}
 

Sync와 Async

- μ•žμ„œ 봀던 μ½”λ“œλ“€μ—μ„œ μ‚¬μš©λ˜λŠ” sync와 async λ©”μ„œλ“œκ°€ μžˆλŠ”λ° μ΄λŠ” GCDμ—μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•  λ•Œ μ‚¬μš©ν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.

 

Sync : νμ— μž‘μ—…μ„ λ™κΈ°μ μœΌλ‘œ μΆ”κ°€ν•˜μ—¬ ν•΄λ‹Ή μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λ‹€λ₯Έ μž‘μ—…μ„ λŒ€κΈ°ν•˜κ²Œ ν•©λ‹ˆλ‹€.

Async : 큐에 μž‘μ—…μ„ λΉ„λ™κΈ°μ μœΌλ‘œ μΆ”κ°€ν•˜μ—¬ λ‹€λ₯Έ μž‘μ—…κ³Ό λ™μ‹œμ— 싀행될 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

 

κ°„λ‹¨ν•˜κ²Œ μ˜ˆμ‹œλ₯Ό λ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

let queue = DispatchQueue(label: "com.example.queue")

// async μ˜ˆμ‹œ
queue.async {
    print("Start async task")
    sleep(1) // 1μ΄ˆκ°„ λŒ€κΈ°
    print("Finish async task")
}

print("μ•Όν˜Έ")

// sync μ˜ˆμ‹œ
queue.sync {
    print("Start sync task")
    sleep(1) // 1μ΄ˆκ°„ λŒ€κΈ°
    print("Finish sync task")
}

print("λ§Œμ„Έ")

 

μœ„μ™€ 같이 μž‘μ„±ν•œ μ½”λ“œμ˜ 경우,  μœ„μ—μ„œ μ„€λͺ…ν–ˆλ˜ κ²ƒμ²˜λŸΌ

async λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œ μž‘μ—…μ΄ 큐에 μΆ”κ°€λœ 직후 λ°”λ‘œ 싀행이 될 κ²ƒμž…λ‹ˆλ‹€.

또 이 μž‘μ—…μ΄ μ™„λ£Œλ˜κΈ° μ „κΉŒμ§€ λ‹€λ₯Έ μž‘μ—…μ€ 기닀릴 ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ—  좜λ ₯ μˆœμ„œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

좜λ ₯μˆœμ„œ : μ•Όν˜Έ -> Start async task -> Finish async task

 

이와 λ‹€λ₯΄κ²Œ sync λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œ μž‘μ—…μ€

큐에 μΆ”κ°€λœ ν›„ ν•΄λ‹Ή μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λŒ€κΈ°ν•΄μ•Ό ν•˜λ―€λ‘œ λ‹€λ₯Έ μž‘μ—…μ΄ μˆ˜ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

결과적으둜 λ‹€μŒκ³Ό 같은 μˆœμ„œλ‘œ 좜λ ₯이 λ©λ‹ˆλ‹€.

 

좜λ ₯μˆœμ„œ : Start sync task -> Finish sync task -> λ§Œμ„Έ

 

μ •λ¦¬ν•˜λ©΄

 

큐에 μž‘μ—…μ„ μΆ”κ°€ν•  λ•Œ async λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄, μž‘μ—…μ€ νμ—μ„œ λΉ„λ™κΈ°μ μœΌλ‘œ μ‹€ν–‰λ©λ‹ˆλ‹€. μž‘μ—…μ΄ μ™„λ£Œλ˜λ©΄ ν•΄λ‹Ή μž‘μ—…μ΄ μ™„λ£Œλ˜μ—ˆλ‹€λŠ” μ‹ ν˜Έκ°€ μ „λ‹¬λ˜μ–΄, λ‹€μŒ μž‘μ—…μ„ μ²˜λ¦¬ν•  수 있게 λ©λ‹ˆλ‹€.

 

λ°˜λ©΄μ—, sync λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄, 큐에 μž‘μ—…μ΄ μΆ”κ°€λœ ν›„, μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λ‹€μŒ μž‘μ—…μ„ λŒ€κΈ°ν•©λ‹ˆλ‹€. μž‘μ—…μ΄ μ™„λ£Œλ˜λ©΄ λ‹€μŒ μž‘μ—…μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•¨μœΌλ‘œμ¨, νμ—μ„œ μ‹€ν–‰λ˜λŠ” μž‘μ—…λ“€μ€ 순차적으둜 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€.

 

κ°„λ‹¨ν•œ μ˜ˆμ‹œ

GCDλ₯Ό μ΄μš©ν•΄ λ„€νŠΈμ›Œν¬ μš”μ²­μ„ ν•˜λŠ” μ˜ˆμ‹œ μ½”λ“œμž…λ‹ˆλ‹€.

 

// λ„€νŠΈμ›Œν¬ μš”μ²­
func fetchImage(url: URL, completion: @escaping (UIImage?, Error?) -> Void) {

    DispatchQueue.global(qos: .background).async {
        do {
            let data = try Data(contentsOf: url)
            let image = UIImage(data: data)
            completion(image, nil)
        } catch {
            completion(nil, error)
        }
    }
}

// μ˜ˆμ‹œ
let url = URL(string: "https://my_image.jpg")!

fetchImage(url: url) { image, error in
    if let error = error {
        return
    }
    
    DispatchQueue.main.async {
        imageView.image = image
    }
}

 

 

fetchImage ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ global queueλ₯Ό μ‚¬μš©ν•˜μ—¬ λ„€νŠΈμ›Œν¬ μš”μ²­ μž‘μ—…μ„ μ‹€ν–‰ν•˜κ³ 

이 λ•Œ, main queueλ₯Ό μ‚¬μš©ν•˜μ—¬ UI μ—…λ°μ΄νŠΈ μž‘μ—…μ„ μ‹€ν–‰ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

 

μ˜€λŠ˜μ€ μ—¬κΈ°κΉŒμ§€ 정리해 λ³΄κ² μŠ΅λ‹ˆλ‹€!

 

global queueλ₯Ό μ‚¬μš©ν•  λ•Œ, qos와 κ΄€λ ¨ν•˜μ—¬λ„ 좔후에 μ •λ¦¬ν•΄μ„œ 

이 ν¬μŠ€νŒ…μ— μΆ”κ°€ν•  μ˜ˆμ •μž…λ‹ˆλ‹€.

 

그럼 이만 πŸ‘‹πŸ»πŸ‘‹πŸ»πŸ‘‹πŸ»

 

 

λ°˜μ‘ν˜•