ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] GCD (Grand Central Dispatch) λž€? (feat. main & global dispatch queue)
    iOS/πŸ€– App 2021. 6. 7. 00:19

    μ•ˆλ…•ν•˜μ„Έμš”. μ˜€λŠ˜μ€ iOS의 λ™μ‹œμ„± ν”„λ‘œκ·Έλž˜λ°μ— 자주 μ‚¬μš©ν•˜λŠ” GCD 에 λŒ€ν•΄μ„œ κ³΅λΆ€ν•˜κ² μŠ΅λ‹ˆλ‹€πŸΆ

     

    그럼 μ‹œμž‘ν•΄λ³Όκ²Œμš”πŸ₯³


    GCD

    GCD λŠ” iOS μ—μ„œ λ©€ν‹°μ½”μ–΄ ν”„λ‘œμ„Έμ„œμ— μ½”λ“œλ₯Ό λ™μ‹œμ— μ‹€ν–‰μ‹œν‚€κ²Œ ν•΄μ£ΌλŠ” ν”„λ ˆμž„μ›Œν¬μž…λ‹ˆλ‹€.

    :: 그리고 macOS, watchOS, tvOS μ—μ„œλ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

     

    GCD μ—μ„œλŠ” ν•˜λ‚˜μ˜ μž‘μ—…λ‹¨μœ„μΈ Task λ₯Ό Dispatch Queue 에 μ „λ‹¬ν•˜κΈ°λ§Œ ν•˜λ©΄ λ‚˜λ¨Έμ§€λŠ” μ‹œμŠ€ν…œμ΄ μ•Œμ•„μ„œ μ²˜λ¦¬ν•˜κ³  μ‹€ν–‰μ‹œμΌœ μ€λ‹ˆλ‹€.

     

    Task 의 λ‹¨μœ„λŠ” λΈ”λ‘μ΄λ‚˜, DispatchWorkItem 의 μΈμŠ€ν„΄μŠ€ ν˜•νƒœλ‘œ μ‘΄μž¬ν•©λ‹ˆλ‹€.

    :: 블둝은 `{ }` 둜 감싸진 μ‹€ν–‰ μ½”λ“œ

     

    BSD ν•˜μœ„ μ‹œμŠ€ν…œμ΄λ‚˜, Core Foundation, Cocoa API듀은 이 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•¨μœΌλ‘œμ„œ μ‹œμŠ€ν…œκ³Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 싀행속도, νš¨μœ¨μ„± 그리고 λ°˜μ‘μ„±μ„ ν–₯μƒμ‹œμΌ°μŠ΅λ‹ˆλ‹€.

     

    μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μˆ˜ν–‰λ˜λŠ” μ‹€ν–‰ ν™˜κ²½ ( ν”„λ‘œμ„Έμ„œμ˜ μ½”μ–΄ 수) 도 제각각이고, λ™μ‹œμ— μ‹€ν–‰ 쀑인 λ‹€λ₯Έ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό μžμ› κ²½μŸμ„ ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ—, ν•˜λ‚˜μ˜ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ‹€μˆ˜μ˜ μ½”μ–΄λ₯Ό 효율적으둜 μ‚¬μš©ν•˜λŠ”κ²ƒμ€ 정말 μ–΄λ €μš΄ μž‘μ—…μž…λ‹ˆλ‹€πŸ™„

     

    ν•˜μ§€λ§Œ μ‹œμŠ€ν…œ λ ˆλ²¨μ—μ„œ κ΅¬λ™λ˜λŠ” GCD λ₯Ό μ‚¬μš©ν•˜λ©΄, ν˜„μž¬ ꡬ동 쀑인 λͺ¨λ“  μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μš”κ΅¬μ‚¬ν•­μ„ 쉽고 더 잘 μΆ©μ‘±μ‹œν‚¬μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.


    GCD λŠ” μ μ ˆν•˜κ³  κ· ν˜•μžˆκ²Œ κ°€μš©ν•œ μ‹œμŠ€ν…œ μžμ›μ„ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ— λΆ„λ°°ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

     

    μš”μ•½:  GCD 에 Task 만 μ „λ‹¬ν•˜λ©΄ μ•Œμ•„μ„œ μ“°λ ˆλ“œ 배정을 ν•΄μ„œ  μ‹€ν–‰μ‹œμΌœμ€€λ‹€. 🍯


     

    GCD μ—μ„œ Queue λŠ” FIFO ν˜•νƒœμ΄λ©°, GCD λŠ” Queue 에 μ „λ‹¬λœ Task 에 μ“°λ ˆλ“œλ₯Ό Queue 의 νŠΉμ„±μ— 맞게 λ°°μ •ν•©λ‹ˆλ‹€.

     

    DispatchQueue ν΄λž˜μŠ€μ—μ„œ Task λ₯Ό μ „λ‹¬μ‹œν‚¬ Queue λ₯Ό 기본적으둜 두 μ’…λ₯˜ κ΄€λ¦¬ν•©λ‹ˆλ‹€.

     

    DispatchQueue λŠ” 메인 μ“°λ ˆλ“œλ‚˜ λ°±κ·ΈλΌμš΄λ“œ μ“°λ ˆλ“œμ—μ„œ Task λ₯Ό 순차적으둜 ( serially ) ν˜Ήμ€ λ™μ‹œμ— (concurrently) μ‹€ν–‰μ‹œν‚€λŠ” 였브젝트 μž…λ‹ˆλ‹€.


     

    Main queue (메인 큐)

     

    κ·Έ 쀑 ν•˜λ‚˜λŠ” Main queue λ‘œμ„œ κ΅¬λ™λ˜λŠ” ν”„λ‘œμ„ΈμŠ€(= μ•±)의 메인 μ“°λ ˆλ“œμ™€ κ΄€λ ¨λœ dispatch queue μž…λ‹ˆλ‹€.

     

    πŸ’‘ Main queue 에 μ „λ‹¬λœ Task λŠ” 항상 Main Thread 에 μ˜ν•΄ μˆ˜ν–‰λ©λ‹ˆλ‹€.

    κ³΅μ‹λ¬Έμ„œμ—μ„œ 찾은 κ·Όκ±°

    이 λΆ€λΆ„μ—μ„œ 논리적 였λ₯˜μ— λΉ μ§ˆμˆ˜λ„ μžˆλŠ”λ°, global queue 에 μ „λ‹¬λœ task 도 λ©”μΈμ“°λ ˆλ“œμ—μ„œ 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€.

    :: 이 상황은 syncλΌλŠ” λ©”μ„œλ“œμ˜ μ„±λŠ₯ μ΅œμ ν™” λ•Œλ¬ΈμΈλ°, 상황 νŒλ‹¨μ€ GCD κ°€ ν•©λ‹ˆλ‹€.

     

     

    Main queueλŠ” νƒ€μž…μ†μ„± main μœΌλ‘œ  μ ‘κ·Όν•  수 있으며 Serial Queue μž…λ‹ˆλ‹€.

     

    즉 ν•˜λ‚˜μ˜ Task κ°€ λ°˜ν™˜(μ™„λ£Œ) λ˜μ–΄μ•Ό κ·Έ λ‹€μŒ μˆœμ„œμ˜ Task λ₯Ό μ‹€ν–‰μ‹œν‚΅λ‹ˆλ‹€.

    // 메인 큐에 동기 λ°©μ‹μœΌλ‘œ 블둝을 μ „λ‹¬ν•˜λŠ” μ½”λ“œ
    DispatchQueue.main.sync {
      print("Hello, world!")
    }
    
    // 메인 큐에 비동기 λ°©μ‹μœΌλ‘œ 블둝을 μ „λ‹¬ν•˜λŠ” μ½”λ“œ
    DispatchQueue.main.async {
      print("Hello, world!")
    }

     


     

    이 뢀뢄을 κ³΅λΆ€ν•˜λ©΄μ„œ 정말 ν—·κ°ˆλ¦¬λŠ” 점

    λ°”λ‘œ μ‹œλ¦¬μ–Ό 큐에 동기/ 비동기 λ°©μ‹μœΌλ‘œ Task λ₯Ό μΆ”κ°€ν•˜λŠ” 것이 λͺ¨λ‘ κ°€λŠ₯ν•˜λ‹€λŠ” 것을 μ΄ν•΄ν•˜λŠ” 것이 μ–΄λ €μ› μŠ΅λ‹ˆλ‹€.

     

    μ‹œλ¦¬μ–Ό νλŠ” λ¨Όμ € λ“€μ–΄μ˜¨ Task λ₯Ό λ¨Όμ € μˆ˜ν–‰ν•΄μ„œ λ°˜ν™˜ν•œ λ‹€μŒ Task λ₯Ό μˆ˜ν–‰ν•œλ‹€λŠ” 것을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

     

    동기 방식은 Task의 μˆ˜ν–‰μ΄ μ™„λ£Œλ˜κΈ° μ „κΉŒμ§€ νƒ€κ²Ÿ 큐에 락을 κ±°λŠ” (λΈ”λ½ν•˜λŠ”) 것 μž…λ‹ˆλ‹€.

     

    λ™κΈ°λŠ” critical section 에 λŒ€ν•œ μ§„μž…μ„ λ…μ ν•¨μœΌλ‘œμ„œ Race Condition 을 λ°©μ§€ν•˜λŠ” 것이 κ·Έ 첫번째 λͺ©μ μ΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

    :: λ°˜λ©΄μ— 비동기 방식은 Task의 μˆ˜ν–‰ μ™„λ£Œλ₯Ό 기닀리지 μ•Šκ³  호좜 μ¦‰μ‹œ λ°˜ν™˜λ©λ‹ˆλ‹€.

     

    κ·Έλž˜μ„œ 메인큐에 이미 μˆ˜ν–‰ 쀑인 λΈ”λ½μ΄μžˆλŠ” μƒνƒœμ—μ„œ DispatchQueu.main.sync { } 을 ν˜ΈμΆœν•˜μ—¬ Task λ₯Ό μ „λ‹¬ν•˜λ©΄, Deadlock 이 λ°œμƒν•©λ‹ˆλ‹€.

     

    λ°˜λŒ€λ‘œ μˆ˜ν–‰ 쀑인 Task κ°€ μ—†λ‹€λ©΄, λ™κΈ°λ‘œ 전달해도 λ¬Έμ œκ°€ μ—†μŠ΅λ‹ˆλ‹€.

     

    μœ„ κ²½μš°μ— λŒ€ν•œ μ˜ˆμ‹œλŠ” λ”°λ‘œ 글을 μž‘μ„±ν•˜μ—¬ κ²Œμ‹œν•˜κ² μŠ΅λ‹ˆλ‹€πŸ˜Ž

     

    κ΄€λ ¨ κΈ€: [iOS] DispatchQueue.main.sync { } λŠ” μ–΄λ–»κ²Œ μž‘λ™ν• κΉŒ?


     

    Global queue (κΈ€λ‘œλ²Œ 큐)

    Task λ₯Ό Qos μˆ˜μ€€μ„ μ§€μ •ν•œ Global dispatch queue 에 μΆ”κ°€ν•˜λ©΄,  GCD λŠ” μ“°λ ˆλ“œ ν’€μ—μ„œ κ°€μš©ν•œ λ°±κ·ΈλΌμš΄λ“œ μ“°λ ˆλ“œμ— Task λ₯Ό ν• λ‹Ή ν•©λ‹ˆλ‹€.

     

    Global queue 에 μΆ”κ°€λœ Task 듀은 concurrently ν•˜κ²Œ μˆ˜ν–‰λ©λ‹ˆλ‹€.

    :: Main queue λŠ” serially

     

    μˆ˜ν–‰μ‹œκ°„μ΄ μ˜€λž˜κ±Έλ¦¬λŠ” μž‘μ—…λ“€μ€ λ°˜λ“œμ‹œ 메인 큐가 μ•„λ‹Œ λ°±κ·ΈλΌμš΄λ“œ μ“°λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” νμ—μ„œ μ‹€ν–‰μ‹œμΌœμ•Όν•©λ‹ˆλ‹€.

    :: λ„€νŠΈμ›Œν¬, 파일 처리 λ“±

    // κΈ€λ‘œλ²Œ 큐에 동기 λ°©μ‹μœΌλ‘œ 블둝을 μ „λ‹¬ν•˜λŠ” μ½”λ“œ
    DispatchQueue.global().sync {
      print("Hello, Global queue!")
    }
    
    // κΈ€λ‘œλ²„ 큐에 비동기 λ°©μ‹μœΌλ‘œ 블둝을 μ „λ‹¬ν•˜λŠ” μ½”λ“œ
    DispatchQueue.global().async {
      print("Hello, Global queue!")
    }

     

     

    μœ„ 사진은 XCode의 Degug Navigatior μ—μ„œ Process view 뢀뢄을 μΊ‘μ²˜ν•œ μ‚¬μ§„μž…λ‹ˆλ‹€.

     

    μœ„μ™€ 같은 κ²½μš°μ—μ„œ Global queue에 Taskλ₯Ό μΆ”κ°€ν•œλ‹€λ©΄, GCDλŠ” Thread 1 (메인 μ“°λ ˆλ“œ) λ₯Ό μ œμ™Έν•œ κ°€μš©ν•œ λ°±κ·ΈλΌμš΄λ“œ μ“°λ ˆλ“œ (Thread 2, 4, 8) 에  Task λ₯Ό ν• λ‹Ήν•©λ‹ˆλ‹€.

     

    이 μ“°λ ˆλ“œμ˜ κ°œμˆ˜λŠ” μ•± μ‹€ν–‰ μ‹œμ μ— 따라 λ‹€λ¦…λ‹ˆλ‹€.

     

     

     

    μΆ”κ°€μ μœΌλ‘œ λ¦¬λ§ˆμΈλ“œ ν•˜κΈ°

    λ™κΈ°μ μœΌλ‘œ Task κ°€ μ „λ‹¬λ˜λ©΄ 전달 μ¦‰μ‹œ 싀행을 μ‹œλ„ν•œλ‹€. ( μ‹œλ„ν•œλ‹€? μ‹€νŒ¨ν•˜λŠ” κ²½μš°λ„ 있기 λ•Œλ¬Έ )

    μ „λ‹¬λœ Task κ°€ μ‹€ν–‰λ˜μ–΄ λ°˜ν™˜λ  λ•ŒκΉŒμ§€ νƒ€κ²Ÿ 큐 λ‚΄μ˜ λͺ¨λ“  Task 의 싀행을 λ©ˆμΆ˜λ‹€. ( = μ“°λ ˆλ“œ λ°°μ • 쀑지)

     

    λΉ„λ™κΈ°μ μœΌλ‘œ Task κ°€ μ „λ‹¬λ˜λ©΄ Task 의 μ‹€ν–‰μ‹œμ μ€ GCD κ°€ κ²°μ •ν•œλ‹€.

     

    μœ„ 두 가지 사싀을 Serial Queue 와 Concurrent Queue에 μ μš©ν•΄λ³΄κ³ , μ–΄λ–»κ²Œ μž‘λ™ν• μ§€ μƒκ°ν•΄λ³΄μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

     

    sync λ©”μ„œλ“œλŠ” κ°€λŠ₯ν•œ 경우 μ „λ‹¬λœ Task λ₯Ό ν˜„μž¬ μ‹€ν–‰ 쀑인 μ“°λ ˆλ“œμ—μ„œ μ‹€ν–‰ν•œλ‹€.

    예λ₯Ό λ“€μ–΄ DispatchQueue.global().sync { } λ₯Ό μ „λ‹¬ν•˜λ©΄ κ°€λŠ₯ν•œ 경우 Main Thread μ—μ„œλ„ 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€.

     

    Main Thread μ—μ„œ global의 concurrent queueκ°€ μ‹€ν–‰λ˜λŠ” λͺ¨μŠ΅

     

     

     

    끝!


    πŸ€–πŸŸ’[우짱의 iOS λΈ”λ‘œκ·Έ]πŸ”΅πŸ’»

    iOSλ₯Ό κ³΅λΆ€ν•˜λ©΄μ„œ 배운 λ‚΄μš©μ„ κΈ°λ‘ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

     

     

    참고 자료: https://developer.apple.com/documentation/dispatch?changes=latest_minor

    참고 자료: https://developer.apple.com/documentation/dispatch/dispatchqueue?changes=latest_minor

     

    λŒ“κΈ€

μ–΄μ œλ³΄λ‹€ λ°œμ „ν•œ λ‚˜