Skip to content

Instantly share code, notes, and snippets.

@DougGregor
Last active December 18, 2020 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DougGregor/59efedbf3e1cd047b04db6ff5e5a5737 to your computer and use it in GitHub Desktop.
Save DougGregor/59efedbf3e1cd047b04db6ff5e5a5737 to your computer and use it in GitHub Desktop.
Actor counters example
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#endif
actor class Counter {
private var value = 0
private let scratchBuffer: UnsafeMutableBufferPointer<Int>
init(maxCount: Int) {
scratchBuffer = .allocate(capacity: maxCount)
}
deinit {
scratchBuffer.deallocate()
}
func next() async -> Int {
let current = value
// Make sure we haven't produced this value before
assert(scratchBuffer[current] == 0)
scratchBuffer[current] = 1
value = value + 1
return current
}
}
func worker(
identity: Int, counters: [Counter], numIterations: Int
) async {
for i in 0..<numIterations {
let counterIndex = Int.random(in: 0 ..< counters.count)
let counter = counters[counterIndex]
let nextValue = await counter.next()
print("Worker \(identity) calling counter \(counterIndex) produced \(nextValue)")
}
}
func runTest(numCounters: Int, numWorkers: Int, numIterations: Int) async {
// Create counter actors.
var counters: [Counter] = []
for i in 0..<numCounters {
counters.append(Counter(maxCount: numWorkers * numIterations))
}
// Create a bunch of worker threads.
var workers: [Task.Handle<Void>] = []
for i in 0..<numWorkers {
workers.append(
Task.runDetached {
usleep(UInt32.random(in: 0..<100) * 1000)
await worker(
identity: i, counters: counters, numIterations: numIterations
)
}
)
}
// Wait until all of the workers have finished.
for worker in workers {
await try! worker.get()
}
print("DONE!")
}
runAsyncAndBlock {
await runTest(numCounters: 10, numWorkers: 100, numIterations: 1000)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment