信号量
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 {
// 挂起任务直到收到信号。
await semaphore.wait()
await doSomething()
}
// 恢复被挂起的任务。
semaphore.signal()
actor可以使用信号量来确保其方法不能并发运行,从而避免"actor重入问题":
actor MyActor {
private let semaphore = AsyncSemaphore(value: 1)
func serializedMethod() async {
// 确保没有两个任务可以同时执行
// serializedMethod()。
await semaphore.wait()
defer { semaphore.signal() }
await doSomething()
await doSomethingElse()
}
}
信号量通常可以限制对资源的并发访问数量:
class Downloader {
private let semaphore: AsyncSemaphore
/// 创建一个最多可以同时运行
/// `maxDownloadCount`个并发下载的Downloader。
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并发:从上面的例子中获取灵感。