具有异步/等待和异步初始化的线程安全快速单例

问题描述 投票:0回答:1

假设我有一个这样写的 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 { ... }

但这似乎也不起作用,我做错了什么?

swift async-await thread-safety singleton actor
1个回答
0
投票

第一个示例(带有

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
原始实例化(避免参与者重入问题)。它有效,但我很难想出一个我想做这样的事情的实际例子。出于多种原因,我认为这是一种反模式。

© www.soinside.com 2019 - 2024. All rights reserved.