Save 37% off PRO during our Black Friday Sale! »

Data Race and Actor

E83d9812e69ae3a29fabfaa6f4986903?s=47 iganin
October 02, 2021

Data Race and Actor

Presentation about data race and actor.

E83d9812e69ae3a29fabfaa6f4986903?s=128

iganin

October 02, 2021
Tweet

Transcript

  1. Data Race and Actor 2021/10/01 Hironobu Iga

  2. Abstract Explain what data race is, and show example of

    it. Then explain how to resolve this issue in old way, and new way. He use serial queue in old way, and Actor in new way.
  3. Agenda • Data Race • Data Race Demo • Old

    Solution with serial queue • Concurrency in Swift 5.5 • New Solution with Actor
  4. Agenda • Data Race • Data Race Demo • Old

    Solution with serial queue • Concurrency in Swift 5.5 • New Solution with Actor
  5. Data Race The unpredictable behavior when some threads access to

    same shared variable data.
  6. Data Race Thread A Thread A var balance = 1000

    func deposit(amount: Int) -> Int BankAccount Considering situation there are thread A and bank account instance. when only thread A access bank account there will be no problem. balance 1000 deposit 1000 -> balance 2000 balance 2000 deposit 1000 -> balance 3000
  7. Data Race Thread A Thread B var Balance = 1000

    func deposit(amount: Int) -> Int BankAccount Consider situation when thread A and thread B access bank account data at the same time.
  8. Data Race Thread A Thread B var balance = 1000

    func deposit(amount: Int) -> Int BankAccount In this case, behavior become unpredictable. For example, when thread A and B access at the same time, read 1000 and deposit value at the same time, then balance may become 2000. balance 1000 deposit 1000 -> balance 2000 balance 1000 deposit 1000 -> balance 2000
  9. Data Race Thread A Thread B var balance = 1000

    func deposit(amount: Int) -> Int BankAccount The result is huge problem ( where my deposit goes… ) balance 1000 deposit 1000 -> balance 2000 balance 1000 deposit 1000 -> balance 2000 Deposit 2000 But only 1000 was added😱
  10. Agenda • Data Race • Data Race Demo • Old

    Solution with fixed queue • Concurrency in Swift 5.5 • New Solution with Actor
  11. Data Race Demo class DataRaceBankAccount { private var balance =

    0 func deposit(amount: Int) -> Int { balance += amount return balance } } DispatchQueue.concurrentPerform(iterations: 10) { i in print(dataRaceBankAccount.deposit(amount: 1000)) }
  12. Data Race Demo let dataRaceBankAccount = DataRaceBankAccount() DispatchQueue.concurrentPerform(iterations: iteration) {

    _ in let balance = dataRaceBankAccount.deposit(amount: 1000) print("dataRaceBankAccount: \(balance)") } DispatchQueue.concurrentPerform will use threads and perform its prop process concurrently. So we can produce situation for data race.
  13. Agenda • Data Race • Data Race Demo • Old

    Solution with serial queue • Concurrency in Swift 5.5 • New Solution with Actor
  14. Old Solution with fixed queue To avoid data race, we

    can use some solutions • lock(semaphore etc) • serial queue I’d like to focus on fixed queue.
  15. Using Serial Queue class QueueBankAccount { private let queue =

    DispatchQueue(label: UUID().uuidString) // serial queue private var balance = 0 func deposit(amount: Int, completion: @escaping ((Int) -> Void)) -> Void { queue.async { [self] in self.balance += amount completion(self.balance) } } } Above class have serial queue, and we can access balance via that queue, which means we can access its balance only via same thread.
  16. Serial Queue Thread A Thread C var balance = 1000

    BankAccount We can access balance only via thread D through deposit function. Thread B Thread D func deposit(amount: Int) -> Int
  17. Serial Queue Demo DispatchQueue.concurrentPerform(iterations: iteration) { _ in queueBankAccount.deposit(amount: 1000)

    { balance in print("queueBankAccount: \(balance)") } }
  18. Agenda • Data Race • Data Race Demo • Old

    Solution with serial queue • Concurrency in Swift 5.5 • New Solution with Actor
  19. Swift 5.5 Concurrency The new concept for concurrency is introduced

    in Swift 5.5. They are async / await, sendable, and actor. actor is today’s main topic.
  20. Async Await Async function with completion handler https://speakerdeck.com/hironobuiga/20210625-meet-async-await-at-swiftai-hao-hui?slide=12 • it

    doesn’t force call completion handler which means we can make bug easily • deep nest • difficult to read because of out of order Async function with async / await https://speakerdeck.com/hironobuiga/20210625-meet-async-await-at-swiftai-hao-hui?slide=17 • it force returning value • no nest, very simple • very simple order from top to bottom
  21. Agenda • Data Race • Data Race Demo • Old

    Solution with serial queue • Concurrency in Swift 5.5 • New Solution with Actor
  22. What is Actor The actor model is a conceptual model

    to deal with concurrent computation. It defines some general rules for how the system’s components should behave and interact with each other. https://www.brianstorti.com/the-actor-model/ Hmmm…. Above definition is too abstract, so let’s check swift usage.
  23. Swift Actor actor Counter { var count = 0 func

    increase() { count += 1 } } • Reference Type • don’t support inheritance • enforce synchronized access to its mutable property / mutation method ◦ it prevent data racing
  24. Swift Actor actor Counter { var count = 0 func

    increase() { count += 1 } } counter.increase() // compile error await counter.increase() Actor enforce synchronized access, so we can access mutable data only via async / await.
  25. Example actor ActorBankAccount { private var balance = 0 func

    deposit(amount: Int) async -> Int { balance += amount return balance } } We can define actor class with using `actor`. As you can see, the definition is very simple and almost same as not actor one.
  26. Actor Demo DispatchQueue.concurrentPerform(iterations: 10) { _ in Task.detached { let

    balance = await actorBankAccount.deposit(amount: 1000) print("actorBankAccount: \(balance)") } } We should use Task {} to use async / await func.
  27. Merit of Actor • it enforce synchronization ◦ when use

    serial queue, it depends on us whether we implement it correctly or not • very simple
  28. But…. We can use swift new concurrency system from Swift

    5.5. But it depends on OS currently. We can use concurrency with above iOS15… Currently swift contributor works on back to older version. And it seems that we will be able to use Swift new concurrency under iOS version under 15. https://forums.swift.org/t/will-swift-concurrency-deploy-back-to-older-oss/49370
  29. Summary When we access to shared data from multi thread

    concurrently, data race and race condition may happen. We usually deal with this kind of problem with using fixed queue. And from Swift 5.5 we can use `Actor` as new way to solve it.
  30. And more • MainActor • GlobalActor • Sendable • etc...