简单并发核心数据

Posted

技术标签:

【中文标题】简单并发核心数据【英文标题】:Simple Concurrent Core Data 【发布时间】:2013-11-04 02:46:48 【问题描述】:

在过去的几天里,我进行了大量研究,但我不确定当前并发核心数据的最佳实践是什么。最相关的帖子似乎是这个blog post,但鉴于this analysis 关于不同并发方法的性能,似乎带有父上下文的现代方式可能不是最好的。此外,来自 Apple 的 this example 没有实现 Apple's own concurrency guide 中提到的最佳实践,即建议不要使用默认的 NSConfinementConcurrencyType。

鉴于所有这些,用 Core Data 实现并发的最简单和最好的方法是什么?我所需要的只是一个后台线程,它可以在不挂断 UI 的情况下对 Core Data 进行一些长时间的写入。代码示例表示赞赏。

【问题讨论】:

【参考方案1】:

与往常一样,这实际上取决于您要完成的工作。

无论您实施何种架构,“长写入”都会挂起您的 UI。 写入操作在 OS 级别和 sqlite 引擎级别锁定 DB 文件(如果您使用这种存储),所有挂起的读取操作都必须等待写入结束才能完成。 最常用的优化方法之一是使用多个保存操作对数据库“加载”过程进行分段(您不应该介意,因为这发生在后台)。

所以,回答这个问题: 对您来说最简单的方法可能是使用您提到的博客文章中描述的架构(父子层次结构)。如果您发现这会导致您的 UI 出现很多“卡顿”,请尝试优化您的数据加载过程或尝试不同的架构。 使用工具在您的应用程序执行中找到“瓶颈”。

CodeData 在我所知道的每个架构中都有“怪癖”/错误,你会逐渐发现它们,这取决于你对它的使用。

【讨论】:

在什么情况下读取必须等待写入完成?我假设有两种上下文,一种用于阅读,一种用于编写,可以解决该问题(可能合并更改时除外)。另外,您能否详细介绍一下您发现了哪些“怪癖”? 写入操作锁定了持久存储协调器(在 CoreData 中,我注意到甚至读取操作也会锁定 PSC)。这意味着没有其他操作(从任何上下文)可以通过该 PSC 进入商店。此外,写入操作将在 SQLite 引擎级别锁定文件(以防止部分写入,然后在写入结束之前读取损坏的数据)。最后,出于同样的原因,一个写操作将文件锁定在 OS 级别。 至于“怪癖”/错误……主要是在合并上下文之间的更改以及获取的结果控制器对它们的反应期间发生的事情。或父子体系结构中不可捕获的异常(与以一对多关系访问已删除对象有关)。还有更多,但它本身就是一篇文章......【参考方案2】:

我的建议是使用父/子上下文模式。根据您提供的稀疏细节(例如记录数、数据总量、交付延迟等)。这似乎是最灵活且经过验证的解决方案,还可以容纳非常大的数据集。

与其他说法相反,无论“写入”到您的数据库多长时间,您都可以拥有流畅运行的 UI。显然,这就是后台线程的用途。保持 UI 流畅的机制是通过所谓的数据更改通知。您可以在不影响用户体验的情况下优雅地对这些做出反应。

您对NSConfinementConcurrencyType 的评论是正确的。正如您的源代码中所述,它是为了向后兼容而存在的,因此您可以忘记它。显然,对于并发,您希望在创建上下文时使用NSPrivateQueueConcurrencyType

【讨论】:

长时间保存(需要几秒钟)正在锁定 PSC,在 PSC 锁定期间触发的任何获取/错误都将等待保存完成 ==> 如果它完成,UI 会卡顿尝试获取未缓存的数据。将数据负载分段为更小的块将减少 PSC 和 UI 卡顿的锁定时间。使用 WAL 也可能有所帮助。

以上是关于简单并发核心数据的主要内容,如果未能解决你的问题,请参考以下文章

关于并发可见性的一点理解

Java核心技术-并发

java核心-多线程-线程类基础知识

java并发核心二Exchanger的使用

Nginx的核心特点

Java核心技术卷一 8. java并发