Swift 并发的一个同步原语
要求: iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ • Swift 5.7+ / Xcode 14+
📖 文档
此包提供了 AsyncSemaphore
,这是一个传统的计数值信号量。
与 DispatchSemaphore
不同,它不会阻塞任何线程。相反,Swift 并发任务会被挂起“等待”信号量。
您可以使用信号量暂停任务并在稍后再恢复它
let semaphore = AsyncSemaphore(value: 0)
Task {
// Suspends the task until a signal occurs.
await semaphore.wait()
await doSomething()
}
// Resumes the suspended task.
semaphore.signal()
一个 actor 可以使用信号量,使得它的方法不能并发执行,避免“actor 可递归进入”问题
actor MyActor {
private let semaphore = AsyncSemaphore(value: 1)
func serializedMethod() async {
// Makes sure no two tasks can execute
// serializedMethod() concurrently.
await semaphore.wait()
defer { semaphore.signal() }
await doSomething()
await doSomethingElse()
}
}
信号量通常可以限制对资源的并发访问数量
class Downloader {
private let semaphore: AsyncSemaphore
/// Creates a Downloader that can run at most
/// `maxDownloadCount` concurrent downloads.
init(maxDownloadCount: Int) {
semaphore = AsyncSemaphore(value: maxDownloadCount)
}
func download(...) async throws -> Data {
try await semaphore.waitUnlessCancelled()
defer { semaphore.signal() }
return try await ...
}
}
您可以在最新的示例中看到,wait()
方法有一个 waitUnlessCancelled
变体,如果任务在发出信号之前被取消,则会抛出 CancellationError
。
有关信号量的妙用,请参阅 Swift 中信号量的美感 🚦。这篇文章讨论了 DispatchSemaphore
,但它可以很容易地移植到 Swift 并发:从上述示例中获得灵感。