Swift 并发的同步原语
要求: iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ • Swift 5.10+ / Xcode 15.3+
📖 文档
此包提供了 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 并发:从上面的例子中获得灵感。