我对快速并发尤其是 Realm Swift 很陌生。我有 2 个示例代码,我认为它们是相同的,但它不起作用
下面是无效代码的示例
var localRealm: Realm {
get {
return try! Realm()
}
}
fileprivate func testAsyncRealm() {
self.localRealm.beginAsyncWrite {
self.localRealm.create(SwiftStringObject.self, value: ["string2"])
self.localRealm.commitAsyncWrite(allowGrouping: true) { error in
print(error)
}
}
}
这段代码会抛出异常
Terminating app due to uncaught exception 'RLMException', reason: Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.
但是,下面的代码可以正常工作
fileprivate func testAsyncRealm() {
let realm = try! Realm()
realm.beginAsyncWrite {
realm.create(SwiftStringObject.self, value: ["string2"])
realm.commitAsyncWrite(allowGrouping: true) { error in
print(error)
}
}
}
我在这里缺少什么?谢谢...
领域版本:10.40.0
这只是一个理论,但符合问题
当领域对象开始异步写入事务时,似乎在该领域上设置了一个标志
isPerformingAsynchronousWriteOperations
以指示它处于异步写入中。例如
var realm = try! Realm()
realm.beginAsyncWrite {
let isWrite = realm.isPerformingAsynchronousWriteOperations
print("is write? \(isWrite)") //outputs true
}
但是,在您的代码(缩写)中
var localRealm: Realm {
get {
return try! Realm()
}
}
fileprivate func testAsyncRealm() {
self.localRealm.beginAsyncWrite {
let isWrite = self.localRealm.isPerformingAsynchronousWriteOperations
print("is write? \(isWrite)") //outputs false
}
}
输出为 false - 表明未设置该标志,因此 Realm 认为它不是异步写入。
我建议这种行为是因为每次通过
self.localRealm
访问 var 时,它都会重新初始化 Realm,并且该标志为 false。
简单的解决方案是使用同一 Realm 实例而不重新初始化它
fileprivate func doAsyncWrite() {
var realm = self.localRealm //gets a realm instance
realm.beginAsyncWrite { //use that same realm to write, which sets the flag
let isWrite = realm.isPerformingAsynchronousWriteOperations
print("is write? \(isWrite)") //returns true
}
}
进行此更改后,问题中的代码可以正常工作。
您捕获了错误的异常,因为您尝试同时异步执行两个写入事务。他们的文档称您一次只需执行一笔交易。您可以通过几个选项来修复它:
@escaping
回调。@propertyWrapper
并注入信号量并实现其逻辑,以避免同时进行多个工作事务。@propertyWrapper
内部实现自己的并发队列并在该队列的包装器内实现所有逻辑是有意义的。Realm 中的这些操作不是线程安全的原因是他们基本上避免“竞争条件”的想法。我们该如何处理它——这取决于我们。
只是他们的文档中关于
asynWrite<Result>(:)
的引用:
此功能与同步
的不同之处在于它会暂停 在等待轮到写入时调用任务而不是阻塞 线。此外,将数据写入磁盘的实际 I/O 是由 后台工作线程。对于小写入,在 主线程阻塞主线程的时间可能比手动阻塞的时间短 将写入分派到后台线程。write
如果区块抛出错误,交易将被取消,任何 错误之前所做的更改将被回滚。
每个 Realm 文件一次只能打开一个写事务。写 事务不能嵌套,并且尝试在 已经处于写事务中的领域将抛出异常。 从其他中相同 Realm 文件的
实例调用write
线程或其他进程将阻塞,直到当前写入事务 完成或取消。Realm
干杯。