假设我有一个这样写的 swift 类,如何确保对 shared() 函数的访问是线程安全的?
class Singleton {
static private var _shared: Singleton?
static func shared() async -> Singleton {
if let shared = _shared {
return shared
}
let shared = await Singleton()
_shared = shared
return shared
}
private init() async {
// Some mandatory async work
}
}
我知道我们可以使用 actors 作为实例,但是我该如何为静态成员做这个呢?
我试着做这样的事情
@globalActor
struct SingletonActor {
public actor SingletonActor {}
public static let shared = SingletonActor()
}
然后将Singleton类标记为@SingletonActor like
@SingletonActor
class Singleton { ... }
但这似乎也不起作用,我做错了什么?
第一个示例(带有
class
方法初始值设定项的 async
和 async
的 shared()
再现)绝对不是线程安全的。而且属性包装方法也行不通。
如果你真的需要一个带有
async
初始化器的单例,我想你可以这样做:
actor Foo {
static private var task: Task<Foo, Never>?
static func shared() async -> Foo {
if let task {
return await task.value
}
let task = Task { await Foo() }
self.task = task
return await task.value
}
private init() async {
// something asynchronous, with an `await`
}
}
这个想法是
actor
消除数据竞争,await
Task
原始实例化(避免参与者重入问题)。它有效,但我很难想出一个我想做这样的事情的实际例子。出于多种原因,我认为这是一种反模式。