Various concurrency related tools, including Lock and async stream additions etc.
dependencies: [
.package(url: "https://github.com/ordo-one/package-concurrency-helpers", .upToNextMajor(from: "0.0.1")),
]
and then add the dependency to your target, e.g.:
.executableTarget(
name: "MyExecutableTarget",
dependencies: [
.product(name: "SwiftConcurrencyHelpers", package: "package-concurrency-helpers")
]),
Safely call a blocking function from an async context:
let result = await forBlockingFunc {
// Call your blocking function here.
}
Run async code in a non-async context:
let result = runSync {
await someFunction()
}
Simple locks, including a variant that sleeps while waiting for the lock:
let lock = Lock()
let result = lock.withLock {
…
}
…and a variant that spins waiting for the lock:
let lock = Spinlock()
let result = lock.withLock {
… // Make sure whatever you do here is quick; other threads may be busy waiting.
}
A simple thread-safe box for a value:
let safeValue = Protected(myValue)
safeValue.write {
// Have exclusive access to the contents here.
$0.someField = true
}
safeValue.read {
// Have exclusive, read-only access to the contents here.
if $0.someField {
…
}
}
An unsafe Sendable
wrapper for value types:
var someNonSendable = …
let wrapper = UnsafeTransfer(someNonSendable)
Task.detached {
let value = wrapper.wrappedValue
// Use `value` here, instead of the original name `someNonSendable`.
}
There is also an UnsafeMutableTransfer
variant, for mutable values.
Yield a value to an AsyncStream
with back-pressure support (waiting in a Concurrency-safe way until the stream is ready to accept the message):
guard yieldWithBackPressure(message: …, to: continuation) else {
// Stream was closed or this task has been cancelled.
}
A simple reference-typed box for value types:
let a = Box(5)
let b = a
b.value += 1
// 'b' and 'a' both now hold 6.
It inherits the Equatable
, Comparable
, CustomStringConvertible
, and CustomDebugStringConvertible
conformances of the contained type.
Determine if a debugger is attached (a Swift version of Apple's C AmIBeingDebugged
):
if isBeingDebugged {
// Running under, or attached by, a debugger of some kind.
} else {
// *Probably* not being debugged.
}
Note that this is not foolproof; debuggers can hide themselves from detection.
A backport of Apple's AsyncStream.makeStream(of:bufferingPolicy:), to make it available in Swift 5.8 and earlier as well.
Calculate the next highest power of two, above a given integer:
let roundedUp = nearestPowerOf2(27)
// 'roundedUp' is 32.
Track the rate of an event, and run a closure every N events:
let monitor = ProcessingRate(interval: 10)
while true {
monitor.checkpoint {
// Runs every 10 calls to `checkpoint`.
print("Current rate: \(monitor.ratePerSecond) Hz")
}
}
Count events, then at designated checkpoints run a closure & reset the count if a set duration has passed since the last reset (or since the counter was created, if never before reset).
let monitor = TimeIntervalCounter(clock: ContinuousClock(),
timeInterval: .seconds(5))
while true {
if monitor.incremenet() {
// It has been at least five seconds since the monitor was last reset.
}
monitor.checkpoint {
// Runs at most once every five seconds.
print("Current count: \(monitor.count)")
// The count will automatically be reset to zero when this closure exits.
}
}
link |
Stars: 7 |
Last commit: 3 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics