Skip to content

Latest commit

ย 

History

History
266 lines (232 loc) ยท 14.3 KB

concurrency.md

File metadata and controls

266 lines (232 loc) ยท 14.3 KB

concurrency๋ž€?

  • synchronous function์„ ํ˜ธ์ถœํ•˜๋ฉด, ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ thread๊ฐ€ block๋œ๋‹ค.
  • asynchronous function์„ ํ˜ธ์ถœํ•˜๋ฉด, ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•˜๋Š” ์ค‘์— thread์—๊ฒŒ ๋‹ค๋ฅธ ์ผ์„ ์‹œํ‚ค๊ณ (suspension) ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ํ•ด๋‹น ์Šค๋ ˆ๋“œ์— ์•Œ๋ ค์ค€๋‹ค.
    • by completion handler,
    • delegate callbacks
    • or returning value (with async keyword)
  • asynchronous function์€ ์‹ค์ œ ํ•จ์ˆ˜๊ฐ€ ์™„๋ฃŒ(complete)๋˜๊ธฐ ์ „์— ๋ฐ”๋กœ returnํ•œ๋‹ค.
  • parallel์€ ์‹ค์ œ๋กœ ๋™์‹œ์—(at the same time) ์—ฌ๋Ÿฌ ์ฝ”๋“œ๋ฅผ ๋™์ž‘์‹œํ‚ด์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์ฃผ๋กœ swift์—์„œ concurrency๋Š” parallel๊ณผ concurrent๋ฅผ ํ•จ๊ป˜ ์ง€์นญํ•œ๋‹ค. 8131DCE0-969B-4CBE-871C-459C4E074177.jpeg
  • medium How to use Appleโ€™s Grand Central Dispatch library to multitask threads like a Pro
  • Introduced in iOS4 (2010)
  • Objective-c๋ถ€ํ„ฐ ์‚ฌ์šฉํ•˜๋˜ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ API
  • implementation of task parallelism based on the thread poll pattern
  • Thread poll์„ developer๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋Œ€์‹  OS๊ฐ€ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ๊ฒƒ
  • GCD works by allowing specific tasks in a program that can be run in parallel to be queued up for execution and, depending on avaliability of processing resources, scheduling then to execute on any of available processor cores

Dispatch Queues

Dispatch Queues are objects that maintain a queue of tasks, either anonymous code blocks or function, and execute these tasks in their turn

  • https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2
  • Library๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ queue๋“ค์„ ์ƒ์„ฑํ•œ๋‹ค.
    • Main queue: runs on the main thread and is a serial queue
    • Global queues: ์ „์ฒด ์‹œ์Šคํ…œ์ด ๊ณต์œ ํ•˜๋Š” concurrent queue. ๊ฐ๊ธฐ ๋‹ค๋ฅธ priority๋ฅผ ๊ฐ–๋Š” ๋„ค ๊ฐœ์˜ ํ๊ฐ€ ์žˆ๋‹ค.
  • client๋„ ์ง์ ‘ queue๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. (Custom queues)
    • serial or concurrent
    • ํ•ด๋‹น Request๋“ค์€ ์‹ค์ œ๋กœ๋Š” global queue๋“ค ์ค‘ ํ•˜๋‚˜์—์„œ ์ž‘๋™๋œ๋‹ค.
  • FIFO queue
  • Serial ๋˜๋Š” Concurrent Type์ด๋‹ค.
    • concurrent queue์—์„œ๋„ task๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰์„ ์‹œ์ž‘ํ•œ๋‹ค.
    • ๋‹จ, suspend ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์ œ ๋‹ค์Œ task๊ฐ€ ์‹œ์ž‘๋  ์ง€, ๋ช‡ ๊ฐœ์˜ task๊ฐ€ ๋™์‹œ์— ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š” ์ง€๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค.
    • GCD๋Š” task๋“ค์„ ๋‹ค๋ฅธ core์—์„œ ์‹คํ–‰์‹œํ‚ค๊ฑฐ๋‚˜, context switch๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ task๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ๋ธ”๋Ÿญ ํ˜•์‹์œผ๋กœ ํƒœ์Šคํฌ๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
  • ์ „๋‹ฌ๋œ ํƒœ์Šคํฌ๋“ค์€ ์‹œ์Šคํ…œ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” thread poll์—์„œ ์ž‘๋™ํ•œ๋‹ค.
  • Avoiding Excessive Thread Creation
    • ํ˜„์žฌ ํ• ๋‹น๋œ ํƒœ์Šคํฌ๋กœ thread๊ฐ€ ๋ธ”๋ฝ๋˜๋ฉด, ์‹œ์Šคํ…œ์€ ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋‹ค๋ฅธ ํ…Œ์Šคํฌ๋“ค์„ ๋™์ž‘์‹œํ‚จ๋‹ค.
    • ๋„ˆ๋ฌด ๋งŽ์€ private concurrent dispatch queue๋ฅผ ์ƒ์„ฑํ•ด๋„ ๋„ˆ๋ฌด ๋งŽ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค.

async/await in Swift

  • WWDC2021์—์„œ ์ฒ˜์Œ ์†Œ๊ฐœ๋จ

Problems with GCD

  • CPU๊ฐ€ ๋ธ”๋ฝ๋  ๋–„๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ thread explosion์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    • thread๋Š” ๊ฐ์ž ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ memory overhead
      • excessive context switch
  • completion handler๋กœ ์ฝ”๋“œ์˜ ์ง๊ด€์„ฑ์ด ๋–จ์–ด์ง€๊ณ , human-error์˜ ์œ„ํ—˜์„ฑ์ด ๋†’์•„์ง„๋‹ค.
func fetchThumbnail(for id: String, completion: @escaping (UIImage?, Error?) -> Void) {
    let request = thumbnailURLRequest(for: id)
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            completion(nil, error)
        } else if (response as? HTTPURLResponse)?.statusCode != 200 {
            completion(nil, FetchError.badID)
        } else {
            guard let image = UIImage(data: data!) else {
		  // completion์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„์„œ caller๋Š” ์—๋Ÿฌ ๋ฐœ์ƒ ์œ ๋ฌด๋ฅผ ์ „๋‹ฌ ๋ฐ›์ง€๋ชปํ•œ๋‹ค.
                return
            }
            image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
                guard let thumbnail = thumbnail else {
                    completion(nil, FetchError.badImage)
                    return
                }
                completion(thumbnail, nil)
            }
        }
    }
    task.resume()
}

Async, Await

  • the keyword await indicates that async function might suspend there
  • async function
    • will finish and return control to your function
    • but it can give up control of the thread in an entirely different way: by suspending
    • (normal function์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•˜๋Š” ๊ฒƒ ์™ธ์— ์ œ์–ด๊ถŒ์„ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋‹ค)
    • async function์€ ํ˜ธ์ถœ๋˜๋ฉด thread์˜ ์ œ์–ด๊ถŒ์„ ๋ถ€์—ฌ๋ฐ›๊ณ , suspension์„ ํ†ตํ•ด ํ•ด๋‹น ์ œ์–ด๊ถŒ์„ system์— ๋„˜๊ธด๋‹ค. (caller function์— ๋„˜๊ธฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค!)
    • system์€ thread์— ๋‹ค๋ฅธ ์ž‘์—…๋“ค์„ ํ• ๋‹นํ•˜๋‹ค๊ฐ€, suspension๋œ function์„ ๋‹ค์‹œ ์ง„ํ–‰ํ•œ๋‹ค.
  • await ํ‚ค์›Œ๋“œ๋Š” suspensionable point๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ํ•ด๋‹น point๋ฅผ ๊ธฐ์ ์œผ๋กœ thread๊ฐ€ ๋ฐ”๋€” ์ˆ˜๋„ ์žˆ๊ณ , ํ•ด๋‹น suspension์— ๋‹ค๋ฅธ ์ž‘์—…์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.
  • await์€ async ํ•จ์ˆ˜์—์„œ๋งŒ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • async ํ‚ค์›Œ๋“œ๋Š” ํ•จ์ˆ˜๊ฐ€ suspensionableํ•จ์„ ์˜๋ฏธํ•œ๋‹ค. ํ•จ์ˆ˜๊ฐ€ suspension๋˜๋ฉด caller๋„ suspension๋œ๋‹ค. ์ฆ‰, async function์˜ caller๋„ async function ์ด์–ด์•ผ ํ•œ๋‹ค.

Implementation

  • ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ async, await์„ ์ด์šฉํ•ด์„œ ํ‘œํ˜„ํ•˜๋ฉด
func fetchThumbnail(for id: String) async throws -> UIImage {
    let request = thumbnailURLRequest(for: id)  
    let (data, response) = try await URLSession.shared.data(for: request)
    guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw FetchError.badID }
    let maybeImage = UIImage(data: data)
   // property๊ฐ€ async๋กœ ์ •์˜๋˜์–ด์žˆ๋‹ค.
    guard let thumbnail = await maybeImage?.thumbnail else { throw FetchError.badImage }
    return thumbnail
}
  • ๊ฐ„๋‹จํ•ด์ง€๊ณ ,์ง๊ด€์ ์ด์–ด์ง„๋‹ค.
  • ๊ธฐ์กด swift์˜ error handling ๋ฐฉ์‹์„ ๊ทธ๋Œ€๋กœ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  • task์˜ dependencies๋“ค์„ ํŠธ๋ž˜ํ‚นํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ๋™๊ธฐํ™” ๊ด€๋ จ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

์ž‘๋™๋ฐฉ์‹

  • thread๋Š” 6๊ฐœ(for iPhone, cpu ๊ฐœ์ˆ˜๋งŒํผ)๋ฐ–์— ์—†๊ณ , lightweight thrad์ธ continuation(function call)์„ ์Šค์œ„์น˜ํ•œ๋‹ค.
  • non-async function์—์„œ๋Š” stack์„ ์ด์šฉํ•ด์„œ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ pop!
  • async function์—์„œ๋Š” stack๊ณผ heap์„ ์ด์šฉ,
    • suspension point(marked with await) ๊ฐ„ ์ „๋‹ฌ ๋  ํ•„์š”๊ฐ€ ์—†๋Š” local variable์„ stack์— ์ €์žฅํ•˜๊ณ 
    • suspension point๊ฐ„ ์ „๋‹ฌ๋  variable์„ heap์— ์ €์žฅ๋œ๋‹ค
    • await ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ continuation switch๋ฅผ ํ†ตํ•ด ์ปจํ…์ŠคํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด stack์— pushํ•˜๋Š” ๋Œ€์‹ , replaceํ•œ๋‹ค.

considerations when using swift concurrency

  1. Performance
    • concurrency๋Š” ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋กœ์ง์„ ํ•„์š”๋กœ ํ•œ๋‹ค.
  2. await ๊ตฌ๊ฐ„์—์„œ thread๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ธฐ์–ตํ•ด์•ผ ํ•œ๋‹ค.
    • atomicity๊ฐ€ ๊นจ์ง€๊ณ ,
    • thread specific data๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.
  3. swift์˜ runtime contract์ธ Forward progress(hreads can always make forward progress)๋ฅผ ์ง€์ผœ์ค˜์•ผ ํ•œ๋‹ค.
    • ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๊ฐˆ์ˆ˜๋ก ์Šค๋ ˆ๋“œ๋ฅผ ๋ธ”๋Ÿญํ•  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜์„ฑ์ด ๋†’์•„์ง„๋‹ค. BDCEE517-31C8-468B-9026-FAEAC95FC052.jpeg
  • ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ํƒœ์Šคํฌ๊ฐ€ ๋” ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„์˜ ํƒœ์Šคํฌ ๋•Œ๋ฌธ์— ์‹คํ–‰๋˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ
  • ๋‘ task๊ฐ„ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ํƒœ์Šคํฌ๋Š” ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ ํƒœ์Šคํฌ๊ฐ€ ์ข…๋ฃŒ๋˜์–ด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.
  • GCD๋Š” low priority queue์˜ QoS๋ฅผ ํ†ต์งธ๋กœ ๋†’์—ฌ์„œ ์ด๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค. FIFO ํ๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ
    • ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด, ์ž์›์„ ๊ณต์œ ํ•˜๋Š” low priority task ์•ž์— ์žˆ๋Š” ์ž‘์—…๋“ค์ด ๋ชจ๋‘ ์‹คํ–‰๋œ ํ›„,
    • low priority task๊ฐ€ ์‹คํ–‰๋˜๊ณ 
    • high priority task๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • Swift Concurrency(async, await)๋Š” FIFO queue ๋Œ€์‹  ์‹œ์Šคํ…œ์ด ์ง์ ‘ ์ž‘์—…์„ ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ํƒœ์Šคํฌ๊ฐ€ ๋ฐ”๋กœ ๋จผ์ € ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

structured concurrency in Swift

Tasks

  • a unit of work that can be run asynchronously as part of your program
  • A unit of asynchronous work.
  • ์ž๋™์œผ๋กœ parallel ๋™์ž‘์„ ์ง€์›ํ•จ
  • ์ƒ์„ฑ๋˜์ž๋งˆ์ž ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜, ์Šค์ผ€์ฅดํ•ด์ค„ ํ•„์š”๋Š” ์—†๋‹ค.
  • Swift compiler๊ฐ€ ์ž๋™์œผ๋กœ concurrency bug๋“ค์„ ์žก์•„์คŒ

Async-let tasks

Sequential binding

  • one flow of execution 29326017-8FEE-449E-8BBF-DABADD931DD3.jpeg

concurrent binding

38E52542-7C9C-4EFD-985C-6C74E31EDDEB.jpeg 2B3B771D-3B52-4D12-82D9-83D7355ADD58.jpeg

  • parent task๋Š” child tasks๋“ค์ด ๋ชจ๋‘ ์™„๋ฃŒ๋œ ์ƒํƒœ์—์„œ๋งŒ ์ข…๋ฃŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๋งŒ์•ฝ child task ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋น„์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋œ๋‹ค๋ฉด, parent task๋„ error๋ฅผ ๋˜์ง„๋‹ค. ๋‚จ์€ unawaited task๋“ค์— ๋Œ€ํ•ด์„œ๋Š” cancel์„ ๋งˆํฌํ•ด๋†“๋Š”๋‹ค.
  • cancel ๋งˆํฌ๋Š” task์™€ ๊ทธ subtask๋“ค์—๊ฒŒ response๊ฐ€ ํ•„์š”์—†์Œ์„ ์•Œ๋ฆฐ๋‹ค.
  • Cancellation is cooperative
    • tasks are not stopped immediately when cancelled
    • code must check for cancellation explictly and wind down execution
    • API๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ํ•ญ์ƒ cancellation์„ ๊ณ ๋ คํ•˜์—ฌ์•ผํ•œ๋‹ค. 32DD4778-5305-4318-8295-2C837BF6F806.jpeg
  • cancellation์„ ๊ณ ๋ คํ•œ ์ฝ”๋“œ
    • cancel์ด ์ผ์–ด๋‚œ ๊ฒฝ์šฐ result์˜ ์ผ๋ถ€๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€๋‹ค
    • fetchOneThumbnail ํ•จ์ˆ˜๊ฐ€ ๋ชจ๋‘ ์™„๋ฃŒ๋œ ์ดํ›„์— ๋‹ค์Œ loop๊ฐ€ ์‹œ์ž‘๋œ๋‹ค.

Group tasks

  • more flexibility (than async-let)
  • A task group is a form of structured concurrency that is designed to provide a dynamic amout of concurrency by calling the withThrowingTaskGroup function
  • group์— ์ถ”๊ฐ€๋˜์ž๋งˆ์ž task๋Š” ์‹œ์ž‘๋œ๋‹ค. 1A66A302-1999-4840-A091-E59D74363933.jpeg 840C3E92-C0A6-4EEF-9966-7F160C58BCCD.jpeg
  • dictionary์— ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Data-race ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • swift compiler๊ฐ€ ์žก์•„์คŒ ใ„ฑใ…‡ใ„ท

Data-race safety

  • Task๋ฅผ ์ƒ์„ฑ๋•Œ ์ด์šฉํ•˜๋Š” closure๋Š” @Sendable closure ํƒ€์ž…์ด๋‹ค.
  • Sendable closure์—์„œ๋Š” mutliple varialble์„ ์ด์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  • ๋Œ€์‹  value type, actors, or class that implement their own synchronization์„ ์ด์šฉํ•ด์•ผํ•œ๋‹ค. 8D34B349-47C9-49D5-B8DD-B35E3C88CEBA.jpeg
  • child tasks inherit priority from parent

Unstructured Tasks

when to use

  • when tasks need to launch for non-async contexts
  • when tasks live beyond the confines of a single scope 66E6E74A-D83C-46EC-BC5C-19A10324A100.jpeg

Detached Tasks

  • unscoped lifetime
  • do not inherit anything form their originating context
  • optional parameters control priority BC57173F-C965-406B-97A9-4F494E9C910A.jpeg

Use async/await with URLSession

URLSession.data

let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
      httpResponse.statusCode == 200 /* OK */ else {
    throw MyNetworkingError.invalidServerResponse
}

URLSession.download

let (location, response) = try await URLSession.shared.download(from: url)
guard let httpResponse = response as? HTTPURLResponse,
      httpResponse.statusCode == 200 /* OK */ else {
    throw MyNetworkingError.invalidServerResponse
}

try FileManager.default.moveItem(at: location, to: newLocation)
  • file์„ ์ž๋™์œผ๋กœ ์ง€์šฐ์ง€ ์•Š์Œ

URLSession.upload

var request = URLRequest(url: url)
request.httpMethod = "POST"

let (data, response) = try await URLSession.shared.upload(for: request, fromFile: fileURL)
guard let httpResponse = response as? HTTPURLResponse,
      httpResponse.statusCode == 201 /* Created */ else {
    throw MyNetworkingError.invalidServerResponse
}

URLSessionTask-specific delegate

  • session, task delegate๊ฐ€ ๋‘˜ ๋‹ค ์žˆ์œผ๋ฉด task delegate๊ฐ€ ์ž‘๋™ํ•œ๋‹ค.
  • Reference type
  • actors allow only one task to access their mutable state at a time
  • which makes it safe for code in multiple tasks to interact with the same instance for an actor
actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int

    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}
  • keyword actor ๋ฅผ ์ด์šฉํ•˜์—ฌ actor๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ์—๋Š” structure๋‚˜ class๋ฅผ ์ด์šฉํ•  ๋•Œ์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋‹ค๋ฅธ ์ ์€, actor์˜ property๋‚˜ method์— ์ ‘๊ทผํ•  ๋•Œ์—๋Š” await ์„ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์ง€์ ์ด suspension point์ผ ์ˆ˜ ์žˆ์Œ์„ ๋“œ๋Ÿฌ๋‚ธ๋‹ค.
  • actor๋Š” ํ•ญ์ƒ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ task๋งŒ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค๋ฅธ task๊ฐ€ ์ด๋ฏธ actor instance๋ฅผ ์ด์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ๋™์ž‘์€ suspension๋œ๋‹ค.
  • actor ๋‚ด๋ถ€์—์„œ ์ž๊ธฐ ์ž์‹ ์˜ property์— ์ ‘๊ทผํ•  ๋•Œ์—๋Š” await์„ ์ด์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
// Prints "25"

Additional References