Actor with "continuous" work loop

I recently tackled an Advent of Code challenge that seemed nice for trying out actors. I solved the puzzle (:tada:) but I'm unsure if I've modeled it well. The challenge required a "continuous" loop to keep sending values to a separate component. Meanwhile, a different component outside of the actor can update the value to be sent.

I was able to cause the work loop to temporarily yield to the receive method by sleeping but I'm not sure if this is the right way to handle this. In particular, I was wondering if there was some way to specify that the receive method has a higher priority than resuming run. I could certainly increase the sleep time to allow for more time to receive values, but it seems that I'm still at risk of building up a backlog of pending receive calls. Is there any visibility into how backlogged the actor's "mailbox" is? Is there a better way to handle this?

actor MyActor {
  private var worker = Worker()
  private var lastValue = -1

  func run() async {
    while !Task.isCancelled {
      worker.run(lastValue)
      await Task.sleep(1)
    }
  }

  func receive(_ value: Int) {
    lastValue = value
  }
}

Not sure if this is better: but you could model it via continuations awaiting on each other.

actor MyActor {
  private var worker = Worker()
  var continuation: UnsafeContinuation<Void, Never>?
  var consumption: UnsafeContinuation<Int, Never>?
  
  func run() async {
    while !Task.isCancelled {
      let continuation = self.continuation
      self.continuation = nil
      worker.run(await withUnsafeContinuation {
        self.consumption = $0
        continuation?.resume()
      })
    }
  }
  
  func send(_ value: Int) async {
    await withUnsafeContinuation {
      self.continuation = $0
    }
    let consumption = self.consumption
    self.consumption = nil
    consumption?.resume(returning: value)
  }
}
Terms of Service

Privacy Policy

Cookie Policy