用于 Swift 并发的实用工具
这是一个非常小的库,包含一些类型和扩展,在处理 Swift 并发系统时可能很有用。
TaskQueue
CheckedContinuation
扩展,用于改进人体工程学Task
扩展,用于在桥接到非异步代码时改进人体工程学NSXPCConnection
扩展,用于安全异步集成MainActor.runUnsafely
,用于解决您无法控制的未正确或未充分注释的代码OwnershipTransferring
,用于在 actor 边界之间移动不可发送的值SendableBox
,用于向编译器谎报 Sendable 一致性RelaxedDispatchQueue
,一个非常薄的 DispatchQueue
包装器,具有宽松的参数可发送性约束let queue = TaskQueue()
queue.addOperation {
await asyncFunction()
await anotherAsyncFunction()
}
// This can can also return the underlying Task, so you can cancel, or await a value
let task = await queue.addOperation {
return await makeValue()
}
let value = try await task.value
// Without .ordered, the execution order of these tasks is not well-defined.
Task.ordered {
event1()
}
Task.ordered(priority: .background) {
event2()
}
Task.ordered {
event3()
}
一些方便的函数,可以简化与现有回调的集成。
func callbackOptionalPair(_ block: @escaping (Int?, Error?) -> Void) {
Task.relayResult(to: block) {
// ... return async value or throw...
}
}
func callbackResult(_ block: @escaping (Result<Int, Error>) -> Void) {
Task.relayResult(to: block) {
// ... return async value or throw...
}
}
func callbackOptionalError(_ block: @escaping (Error?) -> Void) {
Task.relayResult(to: block) {
// ... possibly throw...
}
}
这是一个在 actor 边界之间移动值的工具,以保持编译器满意。 它相当不安全。 您必须非常小心如何访问移动的值。
actor MyActor {
let nonSendable: UnsendableType
init(_ transfer: OwnershipTransferring<UnsendableType>) {
self.nonSendable = transfer.takeOwnership()
}
}
let nonSendable = UnsendableType()
let transfer = OwnershipTransferring(nonSendable)
let myActor = MyActor(transfer) // no warnings!
transfer.hasOwnershipBeenTransferred() // true
transfer.takeOwnership() // this will crash
DispatchQueue
现在具有隐式的 @Sendable
闭包参数。 这是一个极具破坏性的变化,因为它使队列不再作为非 Sendable 状态保护的手段可行。 包装该队列并继续。
let nonSendable = UnsendableType()
let queue = RelaxedDisptachQueue(label: "myqueue")
queue.async {
nonSendable.doThing() // no warnings
}
您可能会想让您的 XPC 接口函数成为 async
。 这种方法不能处理连接失败,并且会违反结构化并发的约定,导致挂起。 有关上下文,请参见文章 "ExtensionKit and XPC"。
这个小的 NSXPCConnection
扩展提供了一种安全的方式进入异步世界。
func withContinuation<Service, T>(
function: String = #function,
_ body: (Service, CheckedContinuation<T, Error>) -> Void
) async throws -> T
CheckedContinuation
上也有一些扩展,可以更轻松地在 XPC 的上下文中使用它。 这些对于从常见的回复模式恢复非常方便。
假设您的代码中有这样的 XPC 服务
protocol XPCService {
func errorMethod(reply: (Error?) -> Void)
func valueAndErrorMethod(reply: (String?, Error?) -> Void)
func dataAndErrorMethod(reply: (Data?, Error?) -> Void)
}
continuation 助手允许像这样的桥接
try await withContinuation { service, continuation in
service.errorMethod(reply: continuation.resumingHandler)
}
try await withContinuation { service, continuation in
service.valueAndErrorMethod(reply: continuation.resumingHandler)
}
// this one will try to use JSONDecoder on the resulting data
try await withContinuation { service, continuation in
service.dataAndErrorMethod(reply: continuation.resumingHandler)
}
这些库可能很有用,绝对值得您查看。
AsyncSequence
的响应式扩展AsyncSequence
我们很乐意收到您的来信! 请提出问题或拉取请求。
请注意,此项目是根据 贡献者行为准则 发布的。 参与本项目即表示您同意遵守其条款。