调用DispatchQueue的sync方法来进行读操作是否安全?

huangapple go评论61阅读模式
英文:

Is it safe to call DispatchQueue sync for read operations?

问题

以下是代码部分的翻译:

public final class UserRegistry {
    
    private var infoMap: [String: User] = [:]

    
    private let queue: DispatchQueue = .init(label: "userRegistry.queue")

    func register(_ user: User) {
        queue.async { [weak self] in
            self?.infoMap[user.id] = user
        }
    }

    func deregister(_ user: User) {
        queue.async { [weak self] in
            self?.infoMap[user.id] = nil
        }
    }

    func getUser(for id: String) -> User? {
        queue.sync {
            infoMap[id]
        }
    }
}

希望这对你有所帮助。如果有任何其他疑问,请随时提出。

英文:

I have a class that reads from and writes to a dictionary using a serial dispatch queue. While the write operations are asynchronous, the read operations are synchronous. I want to avoid the use of a completion handler for reading. Does this create any issues? The issue could range from deadlocks or crashes by calling from the main thread.

public final class UserRegistry {

    private var infoMap: [String: User] = [:]

    
    private let queue: DispatchQueue = .init(label: "userRegistry.queue")

    func register(_ user: User) {
        queue.async { [weak self] in
            self?.infoMap[user.id] = user
        }
    }

    func deregister(_ user: User) {
        queue.async { [weak self] in
            self?.infoMap[user.id] = nil
        }
    }

    func getUser(for id: String) -> User? {
        queue.sync {
            infoMap[id]
        }
    }
}

I tried to create a completion handler and that would cause a series of changes at the call site across the code base. I expect that reading synchrnously should be safe regardless of which thread the consumer calls this from.

Read operation - func getUser(for id: String) -> User?

Write operations - func register(_ user: User) & func deregister(_ user: User)

答案1

得分: 2

可以安全地在读取时使用 sync,在写入时使用 async,不会发生 infoMap 上的死锁或竞争。

甚至不一定需要使用 [weak self],因为捕获 self 的块不会存活很长时间。

你也可能不需要为写操作使用 async。你可以只使用 sync 进行写操作。因为 infoMap 从不被复制,所以不会发生复制写入,而且它只会很少重新分配。因此,写操作几乎总是足够便宜,可以同步运行。

请记住,如果 User 是一个引用类型(或者以其他方式没有值语义),你仍然可能会发生涉及个别 User 对象的竞争。

英文:

Yes, you can safely use sync for reads and async for writes and there will not be any deadlocks or races on infoMap.

You don't even particularly need to use [weak self], since the blocks capturing self won't live long.

You also don't probably need to use async for the writes. You could just use sync for writes too. Because infoMap is never copied, there won't be any copy-on-writes, and it will only be reallocated rarely. Thus the write operations should almost always be cheap enough to be run synchronously.

Keep in mind that if User is a reference type (or otherwise doesn't have value semantics), you might still have races involving individual User objects.

huangapple
  • 本文由 发表于 2023年3月4日 09:20:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75633104.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定