์ด์ „ ๊ธ€์—์„œ ๋™์‹œ์„ฑ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๋‹ค. ํ•˜์ง€๋งŒ iOS์—์„œ๋Š” Thread๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ์ž‘์—…ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ป๊ฒŒ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ• ๊นŒ? ๊ทธ ๋‹ต์ธ GCD์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž. ์‹œ์ž‘ํ•ด๋ณด์ž.

ํ•ด๋‹น ๊ธ€์€ ์‚ฌ๋‚ด ๋ฐœํ‘œ์™€ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Grand Central Dispatch(CGD)

Apple์ด ๊ฐœ๋ฐœํ•œ ๊ธฐ์ˆ ๋กœ, ๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ”„๋กœ์„ธ์Šค ํ™˜๊ฒฝ์—์„œ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง€์›์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค.

  • low level C based API
  • ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ์˜ ์ฑ…์ž„์„ ์‹œ์Šคํ…œ์œผ๋กœ ์ด๋™
  • ์‹œ์Šคํ…œ์ด ํ•„์š”ํ•œ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค๊ณ , ํ•ด๋‹น ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋˜๋„๋ก ์ž‘์—…์„ ์˜ˆ์•ฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ ์‹œ์Šคํ…œ์ด ๊ด€๋ฆฌํ•˜๋Š” Queue๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด๊ฑธ Dispatch Queue๋ผ ํ•œ๋‹ค. ์ด Queue์— ํ•˜๊ณ  ์‹ถ์€ ์ž‘์—…์„ ์ •์˜ํ•ด์„œ ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

Dispatch Queue

  • ํ์— ์ž‘์—…์„ ์ œ์ถœํ•˜๋Š” ๊ตฌ์กฐ
    • FIFO ๊ตฌ์กฐ, ์ถ”๊ฐ€๋œ ์ˆœ์„œ๋Œ€๋กœ ์ž‘์—…์ด ์‹œ์ž‘๋จ
  • ์ž‘์—…์€ ํ•จ์ˆ˜ ๋˜๋Š” Block(clousure in swift)๋กœ ํ‘œํ˜„ํ•œ๋‹ค.
  • Dispatch Queue์— ์ œ์ถœ๋œ ์ž‘์—…์€ ์‹œ์Šคํ…œ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์‹คํ–‰๋œ๋‹ค.
  • ์ž‘์—…์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋˜๋Š” ๋™์‹œ์— ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค
    • ์ด ๋ถ€๋ถ„์€ ์œ„์˜ ๋ฉด์ ‘๊ด€ ์˜ˆ์‹œ์—์„œ, ์ค„ ์ž์ฒด๋ฅผ ํ•œ๊ฐœ๋กœ๋งŒ ์„ธ์šธ ๊ฒƒ์ธ์ง€, ์—ฌ๋Ÿฌ์ค„๋กœ ์„ธ์šธ ๊ฒƒ์ธ์ง€์— ๋Œ€์‘๋˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
    • Serial
      • ์ž‘์—…์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
    • Concurrent Dispatch Queue
      • ๋™์‹œ์— ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
  • ์ž‘์—…์„ ๋™๊ธฐ์ ์œผ๋กœ ํ˜น์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์Šค์ผ€์ฅด๋งํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋™๊ธฐ์ ์œผ๋กœ ์Šค์ผ€์ฅด๋ง ํ•œ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ž‘์—…์ด ์‹คํ–‰์„ ๋งˆ์น  ๋•Œ๊ฐ€์ง€ ์ฝ”๋“œ๋Œ€๊ธฐ
    • ๋น„๋™๊ธฐ์ ์œผ๋กœ ์Šค์ผ€์ฅด๋ง ํ•œ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ž‘์—…์ด ์‹คํ–‰ ์ค‘์—๋„ ์ฝ”๋“œ ์‹คํ–‰

Serial Dispatch Queue

  • ํ์— ์ž‘์—…์ด ์ถ”๊ฐ€๋œ ์ˆœ์„œ๋กœ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์‹คํ–‰
  • ์ด์ „ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ƒˆ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜์ง€ ์•Š๊ณ  ๋Œ€๊ธฐ
  • ๋งŒ์•ฝ ๋‘ ๊ฐœ ์ด์ƒ์˜ Serial Queue๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ตœ๋Œ€ 2๊ฐœ์˜ ์ž‘์—…์„ ๋™์‹œ์— ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Œ
    • ๋ฌผ๋ฆฌ์  ์˜๋ฏธ
    • ํ•˜๋“œ์›จ์–ด ์ฝ”์–ด์ˆ˜์— ๋”ฐ๋ผ ๋ณ‘๋ ฌ ์ˆ˜ํ–‰ ์ œํ•œ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ

์ƒ์„ฑ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” 2๊ฐœ๊ฐ€ ์žˆ๋‹ค. ๋ฐ”๋กœ main queue๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, custom queue๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜.

  • Main Queue
    • DispatchQueue.main
  • Custom Queue
    • DispatchQueue(label: "customSerial")

์—ฌ๊ธฐ์„œ ํ•ด๋‹น Queue๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์˜ต์…˜์„ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค.

Serial Sync Dispatch Queue

let queue = DispatchQueue(label: "SerialSyncQueue")
 
queue.sync {
    print("task 1")
}
queue.sync {
    print("task 2")
}
queue.sync {
    print("task 3")
}
print("Done!")
 
/*
Result
task 1
task 2
task 3
Done
*/
  • queue์— ๋“ค์–ด๊ฐ„ ์ž‘์—…์„ ์šฐ์„ ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ๋™์ž‘์„ ๋๋‚˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ๋‹จ๋ฐฉํ–ฅ์ด๋‹ค.

Serial Async Dispatch Queue

let queue = DispatchQueue.main
 
queue.async {
    print("task 1")
}
queue.async {
    print("task 2")
}
queue.async {
    print("task 3")
}
print("Done???")
 
/*
Done??
Result
task 1
task 2
task 3
*/
  • ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” main thread์— ์ž‘์—…์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ, ํ˜„์žฌ ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ์ž‘์—… ๋’ค์— ์Šค์ผ€์ฅด๋ง์ด ๋˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.
    • Out โ† ์ฝ”๋“œ ์ฝ๊ธฐ task - task 1 - task 2 - task 3 โ† In
  • ๋งŒ์•ฝ custom serial queue๋กœ ํ•œ๋‹ค๋ฉด ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ž‘์—…์ด ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅด๋‹ค.
  • async๋กœ ์„ค์ •ํ•œ ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ธ”๋ฝ์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋œ๋‹ค.
  • ๊ทธ๋ž˜์„œ ๋ผ์ธ์„ ๋ชจ๋‘ ์ฝ๊ณ  ํ•ด๋‹น ๋ธ”๋ฝ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰์‹œ์ผœ ์œ„์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.

async ์™ธ์—๋„ asyncAfter ๋ฉ”์„œ๋“œ๋„ ์žˆ๋‹ค.

  • Dispatch Time

    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
        print("Executes after 2 seconds")
    })
    • ๋‚˜๋…ธ์ดˆ ์ •๋ฐ€๋„๋กœ ์‹œ์Šคํ…œ Clock์— ์ƒ๋Œ€์ ์ธ ์‹œ์ 
  • Dispatch Wall Time

    DispatchQueue.main.asyncAfter(wallDeadline: .now() + 2.0, execute: {
        print("Executes after 2 seconds")
    })
    • ๋งˆ์ดํฌ๋กœ์ดˆ ์ •๋ฐ€๋„๋กœ Wall Clock์— ์ ˆ๋Œ€์ ์ธ ์‹œ์ 
    • 5๋ถ„ ํƒ€์ด๋จธ ๊ฑธ๊ณ , system ์‹œ๊ฐ„์„ 5๋ถ„๋’ค๋กœ ์„ค์ •ํ•ด๋ฒ„๋ฆฌ๋ฉด ๋ฐ”๋กœ ํƒ€์ด๋จธ ์ž‘๋™

Concurrent Dispatch Queue

  • ํ•˜๋‚˜ ์ด์ƒ์˜ ์ž‘์—…์„ ๋™์‹œ์— ์‹คํ–‰ (์ž‘์—…์ด ๋ฌผ๋ฆฌ์  ์Šค๋ ˆ๋“œ๋กœ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚˜๊ฐ€๋Š” ์‹œ๊ฐ„์€ ์žˆ์Œ)
  • ํ•˜์ง€๋งŒ ์‹œ์ž‘์€ ํ์— ์ถ”๊ฐ€๋œ ์ˆœ์„œ๋กœ ์‹œ์ž‘
  • ์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๋”๋ผ๋„ Dequeueํ•œ๋‹ค. ๋ฌผ๋ฆฌ์  ์ฝ”์–ด๊ฐ€ ๋‚จ์•„์žˆ์„ ๊ฒฝ์šฐ, ์•ž ์ž‘์—…์„ 1๋ฒˆ ์ฝ”์–ด์—, ๊ทธ ๋’ค ์ž‘์—…์€ 2๋ฒˆ ์ฝ”์–ด์— ๋„˜๊ธฐ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ํŠน์ • ์‹œ์ ์—์„œ ์‹คํ–‰๋˜๋Š” ๋ฌผ๋ฆฌ์  ์ž‘์—… ์ˆ˜๋Š” ๊ฐ€๋ณ€์ ์ด๊ณ  ์‹œ์Šคํ…œ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„

์ƒ์„ฑ ๋ฐฉ๋ฒ•์€ ์—ญ์‹œ 2๊ฐœ๊ฐ€ ์žˆ๋‹ค.

  • Global Queue
    • DispatchQueue.global()
  • Custom Queue
    • DispatchQueue(label: "CustomConcurrentQueue", attributes: .concurrent)

Concurrent Sync Dispatch Queue

let queue = DispatchQueue.global()
 
queue.sync {
    print("task 1")
}
queue.sync {
    print("task 2")
}
queue.sync {
    print("task 3")
}
print("Done!")
 
/*
Result
task 1
task 2
task 3
Done
*/

concurrent queue๋กœ ์ž‘์—…๋“ค์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๊ณ , concurrent queue์— sync๋กœ ์ž‘์—…์ด ๋“ค์–ด๊ฐ”๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ์˜ task๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฌผ๋ฆฌ์  ์ฝ”์–ด์—๋„ ์ž‘๋™ํ•˜๋”๋ผ๋„(์šฐ์—ฐํžˆ ๊ฐ™์€ ์ฝ”์–ด์ผ์ˆ˜๋„ ์žˆ์Œ) ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์€ ํ›„์— ๋™์ž‘ํ•œ๋‹ค.

Concurrent Async Dispatch Queue

let queue = DispatchQueue.global()
 
queue.async {
    print("task 1")
}
queue.async {
    print("task 2")
}
queue.async {
    print("task 3")
}
print("Done???")
 
/*
Result
task 2
task 1
task 3
Done???
*/

ํ˜„์žฌ ๊ฒฐ๊ณผ๋Š” ์ด๋ ‡์ง€๋งŒ, ๊ฐ task๊ฐ€ queue์— ๋“ค์–ด๊ฐ„ ํ›„, ์‹œ์Šคํ…œ ํ™˜๊ฒฝ๊ณผ ํ˜„์žฌ ์ฝ”์–ด ํ™œ์„ฑ๋„์— ๋”ฐ๋ผ ๋™์ž‘ํ•˜๋Š” ์ˆœ์„œ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์ฆ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์žฅ๋ฐ›์„ ์ˆ˜ ์—†๋‹ค.

์‚ฌ์šฉ ํŒจํ„ด

  • Serial Queue(async) + Main Queue

    let queue = DispatchQueue(label: "serial.queue")
     
    queue.async {
        // Do Some Long-Running Task
     
        DispatchQueue.main.async {
            // Update UI
        }
    }
  • Concurrent Queue(async) + Main Queue

    DispathQueue.global().async {
        // Do Some Long-Running Task
     
        DispatchQueue.main.async {
            // Update UI
        }
    }

Quality of Service (QoS)

Apple์—์„œ ์ œ๊ณตํ•˜๋Š” ์ž‘์—…์˜ ๋ช…์‹œ์ ์ธ ๋ถ„๋ฅ˜

์ด ๋ถ„๋ฅ˜๋Š” ์ž‘์—… ์Šค์ผ€์ฅด๋ง ์‹œ, ์ž‘์—…์˜ ํƒ€์ž…์— ๋”ฐ๋ผ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์•„๋ž˜๋Š” ์šฐ์„  ์ˆœ์œ„์— ๋”ฐ๋ฅธ ๋ถ„๋ฅ˜์ด๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์„ ์ˆ˜๋ก ๋” ๋งŽ์€ ๋ฆฌ์†Œ์Šค๋กœ ๋” ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ง€์ •์€ Queue๋ฅผ ๋งŒ๋“ค ๋•Œ, ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • User Interactive
    • ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
    • animations
  • User Initiated
    • ์‚ฌ์šฉ์ž๊ฐ€ ๋ฌด์–ธ๊ฐ€ ์ž‘์—…์„ ํ•˜์—ฌ ์ฆ‰๊ฐ์ ์ธ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
  • Utility
    • ๋ฐ์ดํ„ฐ ๋‹ค์šด๋กœ๋“œ์™€ ๊ฐ™์ด ์ž‘์—… ์™„๋ฃŒ์— ์˜ค๋žœ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ
    • ๋Œ€๋ถ€๋ถ„์˜ ์ž‘์—…์—์„œ ์‚ฌ์šฉ
  • Background
    • ๋™๊ธฐํ™” ๋ฐ ๋ฐฑ์—…๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ์ˆ˜ ์—†๋Š” ์ž‘์—…์„ ํ•  ๋•Œ ์‚ฌ์šฉ
    • ์•„์ดํฐ์€ ์ €์ „๋ ฅ ๋ชจ๋“œ๋กœ ์„ค์ •ํ•œ ๊ฒฝ์šฐ, ์ž‘์—… ์‹คํ–‰์ด ๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.

QoS๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด default๋กœ ์ง€์ •๋˜๋Š”๋ฐ, default๋Š” User Initiated์™€ Utility ์‚ฌ์ด์— ์กด์žฌํ•˜๋Š” ์ค‘์š”๋„๋ฅผ ๊ฐ€์ง„๋‹ค.

Dispatch Work Item

DispatchQueue ๋˜๋Š” DispatchGroup ์•ˆ์—์„œ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ์บก์Šํ™” ํ•จ

item๋‚ด์—์„œ ์‹คํ–‰๊ฐ€๋Šฅํ•˜๊ณ , dispatchQueue๋กœ ๋„˜๊ฒจ์„œ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

let item = DispatchWorkItem(block: {
    print("task?")
})
 
item.perform() // ํ˜„์žฌ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰

item๋‚ด์—์„œ perform์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.

let item = DispatchWorkItem(qos: .utility, block: {
    print("task")
})
 
DispatchQueue.global().async(execute: item)

ํ˜น์€ ์ด๋ ‡๊ฒŒ Queue์•ˆ์— item ์ž์ฒด๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๊ฒฝ์šฐ๋Š” Queue๋ฅผ ์ง€์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

wait

let item = DispatchWorkItem(block: {
    for _ in 0..<100 {
        print("task")
    }
})
 
DispatchQueue.global().async(execute: item)
 
item.wait()
// ์ž‘์—… ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
print("Done!")

์ž‘์—…์„ global queue๋กœ ๋„˜๊ธฐ๊ณ  ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ๋ฐ›์€ ์ƒํƒœ์—์„œ๋„ ๋„˜๊ธด ์ž‘์—… (๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์ค‘)์„ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋‹ค. wait ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

notify

let item = DispatchWorkItem(block: {
    for _ in 0..<100 {
        print("task")
    }
})
 
DispatchQueue.global().async(execute: item)
 
item.notify(queue: .main, execute: {
    print("Done!")
})
 
print("task is running...")

notify๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ์ž‘์—…์ด ๋๋‚œ ๊ฒฝ์šฐ, ์„ค์ •ํ•ด๋‘” ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

cancel

let item = DispatchWorkItem(block: {
    for _ in 0..<100 {
        print("task")
    }
})
 
item.cancel()
print(item.isCancelled) // true
 
DispatchQueue.global().async(execute: item) // ๋™์ž‘ํ•˜์ง€ ์•Š์Œ

์•„์ง ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ cancel ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ทจ์†Œ๋œ ๊ฒฝ์šฐ ์Šค์ผ€์ฅด๋ง ๋˜์–ด๋„ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

Dispatch Group

ํ•˜๋‚˜ ์ด์ƒ์˜ ์ž‘์—… ์‹คํ–‰์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋ฐฉ๋ฒ•

ํ•œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ API ํ˜ธ์ถœ, Model๋กœ ํŒŒ์‹ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ํ•˜๋‚˜์˜ ์ž‘์—… ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค. ์—ฌ๋Ÿฌ ์ž‘์—…์€ ๊ทธ๋ฃน์— ์—ฐ๊ฒฐํ•˜๊ณ , ๋น„๋™๊ธฐ ์‹คํ–‰์„ ์œ„ํ•ด์„œ ์˜ˆ์•ฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“  ์ž‘์—…์ด ๋๋‚œ ํ›„, Completion Handler๋ฅผ ํ†ตํ•ด ์™„๋ฃŒ ๋™์ž‘์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

Enter/Leave

let group = DispatchGroup()
group.enter()
group.leave()

์—ฌ๋Ÿฌ ์ž‘์—…์ด ์žˆ์„ ๋•Œ, ์‹œ์ž‘ํ•˜๋Š” ์‹œ์ ์—์„œ enter, ์ž‘์—…์ด ๋๋‚ฌ์„ ๋•Œ leave๋ฅผ ํ•ด์ฃผ๊ฒŒ ๋˜๋ฉด, enter ์•„๋ž˜์˜ ์ฝ”๋“œ ๋ธ”๋Ÿญ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์„ ์ˆ˜ ์žˆ๋‹ค. ํ•œ ์Œ์œผ๋กœ ์›€์ง์ธ๋‹ค. enterํ•  ๊ฒฝ์šฐ ๋“ค์–ด๊ฐ„ task count +1ํ•˜๊ณ  leaveํ•  ๋•Œ -1 ํ•œ๋‹ค.

Wait (Synchronous)

let group = DispatchGroup()
 
group.enter()
DispatchQueue.global().async {
    for _ in 0..<100 {
        // some code
    }
    print("task 1 is done")
    group.leave()
}
 
group.enter()
DispatchQueue.global().async {
    for _ in 0..<100 {
        // some code
    }
    print("task 2 is done")
    group.leave()
}
 
group.wait()
print("all tasks are done")

dispatchGroup์— wait๋ฅผ ์ ์–ด์ฃผ๊ฒŒ ๋˜๋ฉด, enter๋กœ ๋“ค์–ด๊ฐ„ task๋“ค์˜ ์ž‘์—…์ด ๋ชจ๋‘ ๋๋‚œ ์‹œ์ ์— ๋‹ค์Œ ๋ผ์ธ์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค.

Notify (Asynchronous)

let group = DispatchGroup()
 
group.enter()
DispatchQueue.global().async {
    for _ in 0..<100 {
        // some code
    }
    print("task 1 is done")
    group.leave()
}
 
group.enter()
DispatchQueue.global().async {
    for _ in 0..<100 {
        // some code
    }
    print("task 2 is done")
    group.leave()
}
 
group.notify(queue: .main, execute: {
    print("All tasks are done.")
})
print("passed the notify code line.)

notify๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, enter๋กœ ๋“ค์–ด๊ฐ„ task๋“ค์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค ์ž‘๋™ํ•  ๋•Œ ์ฝ”๋“œ ๋ธ”๋ฝ์ด ์‹คํ–‰๋˜๋‚˜, wait์ฒ˜๋Ÿผ ๋™๊ธฐ์ ์œผ๋กœ ๋Œ€๊ธฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋น„๋™๊ธฐ๋กœ ์ฝ”๋“œ ๋ธ”๋ฝ์ด ์‹คํ–‰๋œ๋‹ค.

Without Enter/leave

let group = DispatchGroup()
 
DispatchQueue.global().async(group: group, execute: {
    for _ in 0..<100 {
        // some code
    }
    print("task 1 is done")
})
 
DispatchQueue.global().async(group: group, execute: {
    for _ in 0..<100 {
        // some code
    }
    print("task 2 is done")
})
 
group.notify(queue: .main, execute: {
    print("All tasks are done.")
})
print("passed the notify code line.)

ํŒŒ๋ผ๋ฏธํ„ฐ์— group ์ž์ฒด๋ฅผ ๋„˜๊น€์œผ๋กœ์จ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ๋ณด๋‹ค ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•˜๋‹ค.

Dispatch Source

์‹œ์Šคํ…œ ์ด๋ฒคํŠธ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ C๊ธฐ๋ฐ˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜

  • ๋ชจ๋‹ˆํ„ฐ๋ง ํ•  ์ด๋ฒคํŠธ์™€ ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  DispatchQueue ๋ฐ ์ฝ”๋“œ๋ฅผ ์ง€์ •ํ•œ๋‹ค.
  • ์ด๋ฒคํŠธ ๋„์ฐฉ ์‹œ ์ง€์ •ํ•œ ํ์—์„œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

๋ฌด์Šจ ๋ง์ผ๊นŒ..? ์ฝ์–ด์„œ๋Š” ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค.

  • Timer Dispatch Sources
    • ์ฃผ๊ธฐ์ ์ธ ์•Œ๋ฆผ์„ ์ƒ์„ฑ
  • Signal Dispatch Sources
    • UNIX Signal์ด ๋„์ฐฉํ•˜๋ฉด ์•Œ๋ฆผ
  • Memory pressure sources
    • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์•Œ๋ฆผ
  • Descriptor sources
    • ํŒŒ์ผ ๋ฐ ์†Œ์ผ“ ๊ธฐ๋ฐ˜ ์ž‘์—… ์•Œ๋ฆผ
  • Process dispatch sources
    • ํ”„๋กœ์„ธ์Šค ๊ด€๋ จ ์ด๋ฒคํŠธ ์•Œ๋ฆผ
  • Mach port dispatch sources
    • Mach ๊ด€๋ จ ์ด๋ฒคํŠธ ์•Œ๋ฆผ
  • custom dispatch sources
    • ์ง์ ‘ ์„ค์ • ํ›„ ํŠธ๋ฆฌ๊ฑฐ

์˜ˆ์‹œ

let source = DispatchSource.makeTimerSource(queue: .main) 
 
source.setEventHandler {
    print("main queue์—์„œ 1์ดˆ ๋’ค์— ์‹คํ–‰๋จ")
}
 
source.schedule(deadline: .now(), repeating: 1.0)
source.activate()
  1. Source๋ฅผ ๋งŒ๋“ ๋‹ค. ์ด ๋•Œ Queue๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค.
  2. ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ์ž‘์—…์„ ์‹คํ–‰ํ•  ๊ฒƒ์ธ์ง€ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•ด์ค€๋‹ค.
  3. ์Šค์ผ€์ฅด๋ง ์กฐ๊ฑด์„ ์„ ํƒํ•œ๋‹ค.
  4. ์‹คํ–‰ํ•œ๋‹ค.

์ •๋ฆฌ

  • DispatchQueue
    • Serial, Concurrent Queue๊ฐ€ ์กด์žฌํ•œ๋‹ค.
    • ๊ฐ๊ฐ์„ ๋™๊ธฐ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • DispatchWorkItem
    • dispatchQueue์•ˆ์—์„œ ์ž‘๋™ํ•  ์ž‘์—…์„ ์บก์Šํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • DispatchGroup
    • ์—ฌ๋Ÿฌ ์ž‘์—…๋“ค์„ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. Block์‹œ์ผœ์„œ ๋™์ž‘์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
  • DispatchSource
    • ์‹œ์Šคํ…œ ์ด๋ฒคํŠธ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค.

๋‹ค์Œ ๊ธ€์—์„œ๋Š” Operation Queue์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

Reference