ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

 

๐Ÿ“– Actor (1) ์ฝ์œผ๋Ÿฌ๊ฐ€๊ธฐ

 

# Actor ํŠน์ง• ๋ณต์Šต ๐Ÿ“

- Actor๋Š” ๊ทธ๋ƒฅ Swift์˜ ์ƒˆ๋กœ์šด ํƒ€์ž…์ž„. ํด๋ž˜์Šค์™€ ๊ฐ€์žฅ ์œ ์‚ฌ. 

- Swift์˜ ๋‹ค๋ฅธ ๋ชจ๋“  ํƒ€์ž…๋“ค๊ณผ ๋˜‘๊ฐ™์ด ํ”„๋กœํผํ‹ฐ, ๋ฉ”์†Œ๋“œ, ์ด๋‹ˆ์…œ๋ผ์ด์ €, subscripts ๋“ฑ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ.

- ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜, Extension ์—ญ์‹œ ์Œ‰๊ฐ€๋Šฅ

- ์ฐธ์กฐํƒ€์ž… like class

- ํด๋ž˜์Šค์™€ ๋‹ฌ๋ฆฌ Actor๋Š” ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ(mutable state)์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉ.

- ํด๋ž˜์Šค์™€ ๋‹ฌ๋ฆฌ ์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š์Œ.

 

Actor isolation

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์‹ค immutable state๋ฉด Actor๋ฅผ ์“ธ ํ•„์š”๋„ ์—†์ž–์•„์š”? 

๊ทผ๋ฐ ์ง€๊ธˆ (Shared) mutable state์—ฌ์„œ ์ง€๊ธˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์—ฌ์ง€๊ฐ€ ์žˆ๋Š”๊ฑฐใ…‡ใ…‡

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๊ฐ€ Actor๋ผ๋Š” ๊ฑธ ์“ฐ๋Š”๊ฑฐ๊ณ .

Actor๊ฐ€ mutable state์— ๋™์‹œ์— ์ ‘๊ทผํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋‹ˆ๊นŒ! Swift๊ฐ€ ๊ทผ๋ณธ์ ์œผ๋กœ ๋ณด์ฆํ•˜๋‹ˆ๊นŒ!

๐Ÿคท: ๊ทผ๋ฐ Actor ๋‹ˆ๊ฐ€ ๋ญ”๋ฐ,,๋‹ˆ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณดํ˜ธํ•˜๊ฒ ๋‹ค๋Š”๊ฑด๋ฐ..๊ทธ๊ฑฐ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฑด๋ฐ

๐Ÿง‘‍๐Ÿ’ป: Actor isolation. Actor isolation์€ Actor๊ฐ€ mutable state๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ž„.

๐Ÿคท : ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ๋ณดํ˜ธํ•˜๋Š”๋””

 

์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž. BankAccount๋ผ๋Š” Actor๊ฐ€ ์žˆ์Œ.

actor BankAccount {
  let accountNumber: Int
  var balance: Double

  init(accountNumber: Int, initialDeposit: Double) {
    self.accountNumber = accountNumber
    self.balance = initialDeposit
  }
}

๊ทธ๋ฆฌ๊ณ  BankAccount์„ extensionํ–ˆ์–ด 

extension BankAccount {
  enum BankError: Error {
    case insufficientFunds
  }
  
  func transfer(amount: Double, to other: BankAccount) throws {
    if amount > self.balance {
      throw BankError.insufficientFunds
    }

    print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

    self.balance = balance - amount
    other.balance = other.balance + amount  // error: actor-isolated property 'balance' can only be referenced on 'self'
  }
}

extension์—๋Š” transfer(amount: to :) ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ์Œ. 

func transfer(amount: Double, to other: BankAccount) throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount โœ…
  other.balance = other.balance + amount โœ…
}

์ž balance๋ฅผ ์—…๋ฐ์ดํŠธ ์‹œํ‚ค๋Š” ๊ณณ์„ ๋ณด์ž.

 

์ž ๋งŒ์•ฝ์— BankAccount๊ฐ€ class์˜€์œผ๋ฉด 

1. ์œ„ ์ฝ”๋“œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๊ณ  == ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ์•ˆ๋‚˜๊ณ 

2. concurrent code์—์„œ data races๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ.

์™œ๋ƒ? balance๋ฅผ ์—…๋ฐ์ดํŠธ ์‹œํ‚ค๋‹ˆ๊นŒ. 

 

๊ทผ๋ฐ BankAccount๊ฐ€ ์ง€๊ธˆ actor์ž–์•„??

func transfer(amount: Double, to other: BankAccount) throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount โœ…
  other.balance = other.balance + amount ๐Ÿšจ // error: actor-isolated property 'balance' can only be referenced on 'self'
}

other.balance๋ฅผ ์—…๋ฐ์ดํŠธ ์‹œํ‚ค๋Š” ์ชฝ์ด ์ปดํŒŒ์ผ์—๋Ÿฌ๊ฐ€ ๋‚จ. 

์™œ๋ƒ๋ฉด balance๋Š” self์—์„œ๋งŒ ์ฐธ์กฐ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ!!!!! 

other.balance ์ด๋ ‡๊ฒŒ ์ฐธ์กฐ๋งŒํ•ด๋„ ์—๋Ÿฌ๊ฐ€๋‚จ. 

์—๋Ÿฌ๋ฅผ ์ž์„ธํžˆ ๋ณด์ž 

actor-isolated property 'balance' can only be referenced on 'self'

1. actor-isolated property 'balance'

๐Ÿ™‹: balance ํ”„๋กœํผํ‹ฐ๊ฐ€ actor-isolated property์ธ๊ฐ€๋ณด๊ตฐ..

๐Ÿง‘‍๐Ÿ’ป : (๋‘๋‘ฅ) ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค. 

actor๋‚ด์— ์ •์˜๋œ

- stored, computed instance properties

- instance methods

- instance subscripts

๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋‘ actor-isolated ์ƒํƒœ์ด๋‹ค.

 

2. can only be referenced on 'self'

actor-isolated ์นœ๊ตฌ๋“ค์€ ์—ฐ๊ฒฐ๋˜๊ฑฐ๋‚˜ "๊ฒฉ๋ฆฌ๋œ" ํŠน์ • actor๋‚ด์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ๊ฒŒ self๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ actor-isolated ์นœ๊ตฌ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ self๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋œป์ด๋‹ค. 

 

ํŠน1. actor-isolated ์ •์˜๋“ค์€ ๋‹ค๋ฅธ actor-isolated ์ •์˜๋“ค์„ ์ž์œ ๋กญ๊ฒŒ ์ฐธ์กฐ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŠน2. actor-isolated๊ฐ€ ์•„๋‹Œ ์ •์˜๋“ค์€ actor-isolated ์ •์˜๋“ค์— ๋™๊ธฐ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค. 

 

# cross-actor reference

actor ์™ธ๋ถ€์—์„œ actor-isolated ์ •์˜์— ๋Œ€ํ•ด ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์„ cross-actor reference๋ผ๊ณ  ํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ์ฐธ์กฐ๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ค‘ ํ•˜๋‚˜๋กœ ํ—ˆ์šฉ๋œ๋‹ค.

 

1. ๋ถˆ๋ณ€ ์ƒํƒœ์— ๋Œ€ํ•œ cross-actor reference.

actor๊ฐ€ ์ •์˜๋œ ๋™์ผํ•œ ๋ชจ๋“ˆ์˜ ์–ด๋Š ๊ณณ์—์„œ๋‚˜ ํ•ญ์ƒ ํ—ˆ์šฉ. 

(ํ•œ ๋ฒˆ ์ดˆ๊ธฐํ™”๋˜๋ฉด ํ•ด๋‹น ์ƒํƒœ๋Š” actor ๋‚ด๋ถ€์—์„œ๋“ , ์™ธ๋ถ€์—์„œ๋“  ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—)

 

๐Ÿ™‹: ์งˆ๋ฌธ!

actor BankAccount {
  let accountNumber: Int
  var balance: Double

  init(accountNumber: Int, initialDeposit: Double) {
    self.accountNumber = accountNumber
    self.balance = initialDeposit
  }
}

BankAccount์—๋Š” accountNumer๋ž‘ balance๊ฐ€ ์žˆ์ž–์•„!

์•„๊นŒ

other.balance ๐Ÿšจ // error: actor-isolated property 'balance' can only be referenced on 'self'

 

์ด๋ ‡๊ฒŒ balance๋ฅผ ์ฐธ์กฐ๋งŒ ํ•ด๋„ ์—๋Ÿฌ๋‚ฌ์œผ๋‹ˆ๊นŒ 

ohter.accountNumber

์ด๊ฒƒ๋„ ์—๋Ÿฌ๋‚˜๊ฒ ๋„ค? 

๐Ÿง‘‍๐Ÿ’ป: ์•„๋‹ˆ๋‹ค. 

func transfer(amount: Double, to other: BankAccount) throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount โœ…
  other.accountNumber โœ…
}

other์˜ accountNumber์— ์ ‘๊ทผํ•˜๋Š”๊ฑด ๊ดœ์ฐฎ์Œ. 

์™œ๋ƒ? 

accountNumber๋Š” let์œผ๋กœ ์„ ์–ธ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๋ณ€ ์ƒํƒœ์— ๋Œ€ํ•œ cross-actor reference์— ํ•ด๋‹น๋œ๋‹ค.

 

๐Ÿšจ [์ฃผ์˜] ๐Ÿšจ

actor๊ฐ€ ์ •์˜๋œ ๋™์ผํ•œ ๋ชจ๋“ˆ์˜ ์–ด๋Š ๊ณณ์—์„œ๋‚˜ ํ•ญ์ƒ ํ—ˆ์šฉ. 

์ฆ‰, actor๊ฐ€ ์ •์˜๋œ ๋ชจ๋“ˆ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ๋Š” ํ—ˆ์šฉ์ด ์•ˆ๋œ๋‹ค๋Š” ๋œป์ด๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž.

public actor BankAccount {
    public let accountNumber: Int
    public var balance: Double

    public init(accountNumber: Int, initialDeposit: Double) {
    self.accountNumber = accountNumber
    self.balance = initialDeposit
  }
}


// Same module
public class MyStaticLibrary {

    public init() {
        let account = BankAccount(accountNumber: 1, initialDeposit: 10)
        print(account.accountNumber) โœ…
    }
}

์ด๋ ‡๊ฒŒ ๊ฐ™์€ ๋ชจ๋“ˆ์•ˆ์— ์ •์˜๋˜์–ด์žˆ์œผ๋ฉด accountNumber๊ฐ€ let์ด๋ฏ€๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

ํ•˜์ง€๋งŒ, ์™ธ๋ถ€ ๋ชจ๋“ˆ์—์„œ๋Š”

func outside_moudle_method() โœ… async โœ… {
    let account = BankAccount(accountNumber: 1, initialDeposit: 10)
    print(โœ… await โœ… account.accountNumber) โœ…
}

๋ฐ˜๋“œ์‹œ ๋น„๋™๊ธฐ ํ˜ธ์ถœ๋กœ ์ฐธ์กฐํ•ด์•ผํ•œ๋‹ค. 

 

๐Ÿคท : ์•„๋‹ˆ ์™œ ์ด๋Ÿฐ..?

๐Ÿง‘‍๐Ÿ’ป : ๋งŒ์•ฝ์— BankAccount๊ฐ€ ์ •์˜๋˜์–ด์žˆ๋Š” ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ณ๋ณด์ž.

๋‚ด๊ฐ€ accountNumber๋ฅผ let์œผ๋กœ ์„ ์–ธํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—๋Š”

print(account.accountNumber) โœ…

๊ทธ๋ƒฅ ์ด๋Ÿฐ ์ฝ”๋“œ๊ฐ€ ์žˆ์–ด.

๊ทผ๋ฐ ๋‚ด๊ฐ€ ๋ชจ์ข…์˜ ์ด์œ ๋กœ ์ธํ•ด์„œ accountNumber๋ฅผ var๋กœ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค๊ณ  ์ณ๋ณด์ž?

๊ทผ๋ฐ var๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ๋งŒ ๋ผ (์™ธ๋ถ€์—์„œ ์ฐธ์กฐํ•ด์•ผํ•˜๋‹ˆ๊นŒ) 

์ฆ‰,  BankAccount๋ชจ๋“ˆ์„ ์“ฐ๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ ์ „๋ถ€ ๋ฐ”๋€Œ์–ด์•ผํ•œ๋‹ค๋Š” ์†Œ๋ฆฌ..

 

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ๊ทธ๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก, ์ฆ‰ ํด๋ผ์ด์–ธํŠธ๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก

๋ชจ๋“ˆ ์™ธ๋ถ€์—์„œ๋Š” let์ด๋“  var๋“  ๋น„๋™๊ธฐ๋กœ ์ฐธ์กฐํ•ด์•ผํ•œ๋‹ค๋Š”๊ฑฐ!

 

1. ๋ถˆ๋ณ€ ์ƒํƒœ์— ๋Œ€ํ•œ cross-actor reference. โœ…

2. ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ํ˜•์‹

๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ์€ actor๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ํ•ด๋‹น์ž‘์—…์„ ์‹คํ–‰ํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” "๋ฉ”์‹œ์ง€"๋กœ ๋ฐ”๋€๋‹ค.

์ด๋Ÿฌํ•œ ๋ฉ”์‹œ์ง€๋Š” actor์˜ ๋ฉ”์ผ๋ฐ•์Šค์— ์ €์žฅ๋˜๋ฉฐ,

๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์‹œ์ž‘ํ•œ ํ˜ธ์ถœ์ž๋Š” actor๊ฐ€ ๋ฉ”์ผ๋ฐ•์Šค์—์„œ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„๋•Œ ๊นŒ์ง€ ์ผ์‹œ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ๋‹ค. 

actor๋Š” ๋ฉ”์ผ๋ฐ•์Šค์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ, ๊ถ๊ทน์ ์œผ๋กœ actor๋Š” 2๊ฐœ ์ด์ƒ์˜ ๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค. 

์ฆ‰, ์ฝ”๋“œ ์ž์ฒด์— ๋™์‹œ์„ฑ์ด ์—†์–ด์ง€๊ฒŒ ๋•Œ๋ฌธ์— Data race๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค. 

 

์ž, ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž.

๋‚ด๊ฐ€ ์ด์ฒด๋ฅผ ํ–ˆ์œผ๋‹ˆ๊นŒ 

func transfer(amount: Double, to other: BankAccount) throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount โœ…
  other.balance = other.balance + amount ๐Ÿšจ // error: actor-isolated property 'balance' can only be referenced on 'self'
}

๋‚ด ์ž”์•ก์€ ์ด์ฒดํ•œ ์–‘ ๋งŒํผ ์ค„์–ด๋“ค์–ด์•ผ ํ•˜๊ณ , 

๋‚ด๊ฐ€ ์ด์ฒดํ•œ ๋‹ค๋ฅธ ๊ณ„์ขŒ์˜ ์ž”์•ก์€ ๋‚ด๊ฐ€ ์ด์ฒดํ•œ ์–‘๋งŒํผ ๋Š˜์–ด๋‚˜์•ผํ•œ๋‹ค.

ํ•˜์ง€๋งŒ, balance๋Š” actor-isolated ํ”„๋กœํผํ‹ฐ์ด๊ธฐ ๋•Œ๋ฌธ์—..self๊ฐ€ ์•„๋‹Œ other๋กœ balance์— ์ ‘๊ทผ์„ ๋ชปํ•˜๋Š” ์ƒํ™ฉ.

์ด๊ฑธ 2๋ฒˆ์œผ๋กœ ํ•ด๊ฒฐํ•ด๋ณด์ž.

extension BankAccount {
  func deposit(amount: Double) โœ… async โœ… {
    assert(amount >= 0)
    balance = balance + amount
  }
}

๋จผ์ € BankAccount์— deposit์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ, async๋กœ ์„ ์–ธํ•ด์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  

func transfer(amount: Double, to other: BankAccount) โœ… async โœ… throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount 
  await other.deposit(amount: amount) โœ…
}

 other์˜ deposit์„ ํ˜ธ์ถœํ•ด์ค€๋‹ค.

deposit์ด async๋กœ ์ •์˜๋˜์–ด์žˆ์œผ๋‹ˆ await์œผ๋กœ ํ˜ธ์ถœํ•ด์ฃผ์ž.

transfer๋‚ด์—์„œ async๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— transfer๋Š” async๋กœ ์ •์˜ํ•ด์ค˜์•ผํ•œ๋‹ค. 

์œ„์—์„œ ๋ฉ”์‹œ์ง€/๋ฉ”์ผ๋ฐ•์Šค๋กœ ์˜ˆ๋ฅผ ๋“ค์—ˆ์œผ๋‹ˆ 

await other.deposit(amount: amount) โœ…

์ด๊ฒƒ์„ ๋ฉ”์‹œ์ง€/๋ฉ”์ผ๋ฐ•์Šค๋กœ ๋ฐ”๊ฟ” ๋งํ•ด๋ณด์ž. 

1. deposit์ด ๋ฉ”์‹œ์ง€๊ฐ€ ๋˜๋ฉฐ

2. other actor์˜ ๋ฉ”์ผ๋ฐ•์Šค์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.

3.  other actor๋Š” ๋ฉ”์ผ๋ฐ•์Šค์—์„œ ์ž‘์—…์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ(retrieves the operation) ์‹คํ–‰ํ•œ๋‹ค.

4. other์˜ balance๊ฐ€ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค. 

 

cross-actor reference๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์ „๋ถ€ ์•Œ์•„๋ณด์•˜๋‹ค. 

1. ๋ถˆ๋ณ€ ์ƒํƒœ์— ๋Œ€ํ•œ cross-actor reference. โœ…

2. ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ํ˜•์‹ โœ…

 

# Compile-time actor-isolation checking

์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ์ด๋ฃจ์–ด์ง€๋Š” actor-isolation checking์€ 

1. cross-actor references์ธ์ง€ ํ™•์ธํ•˜๊ณ 

2. ์ด๋Ÿฌํ•œ ์ฐธ์กฐ๊ฐ€ ์œ„์—์„œ ์„ค๋ช…ํ•œ 2๊ฐ€์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด actor ์™ธ๋ถ€์˜ ์ฝ”๋“œ๊ฐ€ actor์˜ mutable state๋ฅผ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ด๊ฒƒ์ด!!!!!!!!!!!!!

์ง„์งœ ์ด๊ฑธ ๊ฐœ๊ธธ๊ฒŒ ๋งํ–ˆ๋Š”๋ฐ, ์ด๊ฒŒ Actor๊ฐ€ mutable state๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ๊ฑฐ. 

 

# Advanced

์œ„์—์„œ deposit์„ async๋กœ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค. 

extension BankAccount {
  func deposit(amount: Double) โœ… async โœ… {
    assert(amount >= 0)
    balance = balance + amount
  }
}

ํ•˜์ง€๋งŒ ์ž˜ ๋ณด๋ฉด, deposit์€ async๋กœ ๊ตฌํ˜„ ๋  ํ•„์š”๋Š” ์—†๋‹ค.

(deposit์•ˆ์—์„œ await๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๊ฒƒ๋„ ์•„๋‹ˆ๋ผ์„œ)

๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ์—๋Š”

extension BankAccount {
  func deposit(amount: Double) {
    assert(amount >= 0)
    balance = balance + amount
  }
}

๋™๊ธฐํ•จ์ˆ˜(sync)๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค. 

๐Ÿคท: ์•„๋‹ˆ

await other.deposit(amount: amount) โœ…

์ด๋ ‡๊ฒŒ await ํ–ˆ๋Š”๋ฐ, async๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•˜๋Š”๊ฑฐ ์•„๋‹ˆ์•ผ? ์ปดํŒŒ์ผ ์—๋Ÿฌ ์•ˆ๋‚˜?

๐Ÿง‘‍๐Ÿ’ป : ใ…‡ใ…‡์•ˆ๋‚˜..

func non_async_method() {}

func zedd() async {
    await non_async_method()
}

async ์•ˆ์—์„œ await + sync ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๊ฑด ์ปดํŒŒ์ผ ์—๋Ÿฌ์— ํ•ด๋‹น์ด ์•ˆ๋œ๋‹ค. 

๋‹ค๋งŒ

No 'async' operations occur within 'await' expression

์ด๋Ÿฐ ๊ฒฝ๊ณ ๊ฐ€ ๋œฐ ๋ฟ...

await other.deposit(amount: amount) โœ…

extension BankAccount {
  func deposit(amount: Double) {
    assert(amount >= 0)
    balance = balance + amount
  }
}

์š”๊ฑด ๊ทธ๋Ÿฐ ๊ฒฝ๊ณ ๋„ ์•ˆ๋œฌ๋‹ค.

์ด์œ ๋ฅผ ์•Œ์•„๋ณด์ž. 

์œ„์—์„œ ๊ณ„์† ๋ดค๋“ฏ์ด BankAccount๋Š” actor๋กœ ์ •์˜๋˜์–ด์žˆ๋‹ค. 

actor BankAccount {..}

extension BankAccount {
  func deposit(amount: Double) {
    assert(amount >= 0)
    balance = balance + amount
  }
}

deposit์€ ๊ทธ๋Ÿฐ actor ํƒ€์ž… ์•ˆ์˜ sync ๋ฉ”์†Œ๋“œ์ด๋‹ค.

sync ๋ฉ”์†Œ๋“œ์—ฌ๋„ 

actor ์™ธ๋ถ€์—์„œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ await ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ์จ์•ผํ•˜์ง€๋งŒ, 

// actor ์™ธ๋ถ€ 
let account = BankAccount(accountNumber: 1, initialDeposit: 100)
await account.deposit(amount: 10)

actor ๋‚ด๋ถ€์—์„œ๋Š” ๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ await ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ™์ด ์จ์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ cross-actor reference ์ผ๋•Œ๋Š”!!!!!!!! ๋น„๋™๊ธฐ ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜๋‹ค. ์ฆ‰, await๊ณผ ํ•จ๊ป˜ ์จ์•ผํ•œ๋‹ค.

1. actor ๋‚ด๋ถ€์—์„œ๋Š” ๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

extension BankAccount {
  // Pass go and collect $200
  func passGo() {
    self.deposit(amount: 200.0)  // synchronous is okay because `self` is isolated
  }
}

2. cross-actor reference ์ผ๋•Œ๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜๋‹ค.

func transfer(amount: Double, to other: BankAccount) โœ… async โœ… throws {
  if amount > self.balance {
    throw BankError.insufficientFunds
  }

  print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")

  self.balance = balance - amount 
  await other.deposit(amount: amount) โœ…
}

 

์‚ฌ์‹ค Actor์˜ ์กด์žฌ๋Š” ๋„ˆ๋ฌด๋‚˜๋„..ํฐ ๋ณ€ํ™”์ด๊ธฐ ๋•Œ๋ฌธ์— 

WWDC 21 Protect mutable state with Swift actors๋ฅผ ๋ณด๋ฉด์„œ..๊ฝค ์˜ค๋žซ๋™์•ˆ ์จ์˜ค๋˜ ๊ธ€์ธ๋ฐ์š”. 

์š” Actor isolation์— ๋ถ€๋”ชํ˜€์„œ ใ…œใ…œ ์ง„์งœ ๋„๋ฌด์ง€ ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€์„œ ๊ฐœ์งฑ๋‚œ๋‹ค..์•ˆํ•ด ** ์ด์ƒํƒœ๋กœ ๋ช‡์ฃผ... 

swift-evolution์˜ actor proposal์„ ๋ณด๋‹ˆ๊นŒ ์–ด๋Š์ •๋„ ์ดํ•ด๊ฐ€ ๊ฐ‘๋‹ˆ๋‹ค.

๐Ÿค” ์—ฌ์ „ํžˆ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„์€ ์žˆ์ง€๋งŒ ใ…Žใ…Ž...

ํ˜น์‹œ ํ‹€๋ฆฐ์ ์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์„ธ์š” ๐Ÿ™‡‍โ™€๏ธ

 

[๋‹ค์Œ ๊ธ€ ์ฝ์œผ๋Ÿฌ๊ฐ€๊ธฐ]

Actor (3) - isolated parameter / nonisolated keyword


 

๋ฐ˜์‘ํ˜•

'Swift > Concurrency' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Combine โ†’ Swift Concurrency(async/await)๋กœ ๋ฐ”๊พธ๊ธฐ (feat. ๋Š๋‚€์ )  (3) 2022.01.25
Actor (4) - Sendable  (3) 2021.10.11
Swift ) Actor (3) - isolated parameter / nonisolated keyword  (1) 2021.08.29
Swift ) Actor (1)  (5) 2021.08.22
[Swift Concurrency] Async/await  (11) 2021.03.25