ios - 导入非常大的数据集时的CoreData和RestKit性能

标签 ios performance core-data restkit

我正在使用RestKit在(iOS平台上的)各种端点上获取JSON数据。

关于SO的几个问题都指向与该问题相同的方向:

Importing large datasets on iPhone using CoreData

但是我的问题仍然是一个不同的问题,因为我知道,如果JSON文件太大,我必须将其切成块。我会去做的!

使用RestKit中的CoreData完全可以完成导入。
似乎有一个父/子上下文设置,当在最短的时间内导入大型数据集时,这是效率很低的(也许在启动时一次全部-没有批处理/延迟导入!!! )。

See here a post from Florian Kugler on performant importing in CoreData (Stacks)

我的问题是:除了已经使用RestKit进行的父/子上下文设置之外,我是否可以设置其他上下文,并在其他上下文上运行完全导入异步操作的RKManagedObjectRequestOperation。然后将上下文合并到mainContext中以进行提取...

我真的想坚持使用CoreData而不是切换到普通的SQLite,以便从CoreDataRestKit的组合中获得最大的性能。

您的专业答案让我感到很高兴。也许布雷克也可以直接回答我这个问题。

最佳答案

好吧,首先,如果您想要最大的性能,并且如果您确实需要最大的性能,请不要使用RestKit,请不要使用AFNetworking,也不要使用NSJSONSerialization。它们都遭受设计选择的困扰,这些选择在处理大数据集时以及您的目标是保持适度的低内存占用量和高性能时不能很好地发挥作用。

您应该拥有一个非常大的单个JSON(可能是一个JSON Array,其元素是JSON对象)作为单个连接的主体,以实现出色的性能。另外,您可以使用一种自定义传输格式,该格式可以在一个连接中发送多个JSON(例如,一系列JSON对象,用“空白”分隔)。

拥有大量连接绝对是缓慢的。

当您努力实现最快的性能时,应该同时下载,解析JSON,创建表示并将其保存到持久性存储中。

笔记:

并行执行所有操作时,您特别容易受到连接错误的影响,保持一致和逻辑正确的数据集可能会成为挑战。因此,如果您的连接质量较差且经常中断,则可以先下载JSON文件并将其保存到临时文件(还支持HTTP范围 header ,以暂停和继续下载)。当然,您的性能会下降-但是在这种情况下,无论如何您都无法使其快速发展。

同样,当您的目标是实现最佳性能时,您应该利用所有CPU的功能,这些功能应在合理的范围内并行运行-特别是在连接速度较快的情况下。

JSON解析器还应该能够解析NSData对象中包含的“块”(即部分JSON),因为这是我们从connection:didReceiveData:获得的。

收到JSON数据时,需要将其“映射”为合适的表示形式。通常,已知的JSON解析器会创建“基础表示形式”。但是,更快的方法是直接从JSON创建最终所需的对象类型。这需要一个“SAX样式API”(基本上是解析器的简化版本,该解析器会将“解析事件”发送给委托(delegate)人或客户端),例如“got JSON-Array begin”或“got JSON Boolean False”,等等。接收这些事件并即时构造所需对象的自定义代码。

这一切都需要一个JSON解析器,该解析器具有NSJSONSerialization中找不到的功能:SAX-Style API,“块解析”或解析一系列JSON文档的输入。

为了最大程度地利用CPU,磁盘和网络,您可以将“任务”分为与CPU绑定(bind),与I/O绑定(bind),分别与网络绑定(bind)的操作,并创建与系统相同数量的并并行运行的数量。这些任务基本上全部异步运行,接受输入,处理输入,并产生输出,该输出是下一个异步任务的输入。当完成时,第一个任务会通知下一个任务,例如,通过完成处理程序(块),并通过参数传递其输出。

处理JSON数据的传入“块”(即解析并创建表示形式)是CPU绑定(bind)的操作。但是,这通常非常快,我不认为通过并发队列在所有可用的CPU上分配这些受CPU约束的任务是不值得的。

基本上可以通过两种方法来处理传入的JSON数据“块”,这两种方法各有利弊:

异步处理部分JSON数据

当您在connection:didReceiveData:中收到“块”时,可以将其异步调度到另一个队列上,以进行与委托(delegate)不同的线程上运行的处理(即解析和创建表示形式)。

优点:委托(delegate)立即返回,因此不会阻塞委托(delegate)线程,从而导致最快地读取传入的网络数据和较小的网络缓冲区。连接在最短的时间内完成。

缺点:如果与接收数据相比处理速度较慢,则可以在块中将大量NSData对象排队,等待在串行调度队列中执行。这将保留为每个NSData对象分配的内存-除非最终采取适当的措施,否则系统RAM最终可能会耗尽,并且可能会收到内存警告或崩溃。

同步处理部分JSON数据

当接收到一部分JSON时,解析器将相对于委托(delegate)线程被同步调用。

优点:
与接收数据相比,当数据处理速度较慢时,这可以避免出现内存问题。但是,这最终可能会阻止从网络读取数据(一旦内部接收缓冲区已满)。

缺点:
如果处理缓慢并且内部网络缓冲区已满,则这将增加连接 Activity 的时间,从而增加连接断开的可能性。

两种方法都受益于快速解析器/表示生成器,并且需要一种解析器,该解析器可以将JSON的“块”作为NSData对象进行处理,并在完成表示时异步通知客户端。 (可选)它还应具有“SAX样式” API。我知道有两个第三方JSON解析器可以满足这些要求:

jsonlite和这个

JPJson

两者都非常快(比JSONKit和NSJSONSerialization更快),支持SAX样式解析,并且可以作为NSData对象以块的形式处理JSON。 JPJson还可以处理包含多个JSON的文件。

(公开:我是JPJson的作者)

创建表示后,下一步就是创建和初始化托管对象(除非解析器直接生成托管对象),然后将对象保存到持久性存储中。这是一个I/O和CPU绑定(bind)操作-但使用SSD存储时可能会绑定(bind)更多CPU。我会将这个过程安排在一个单独的队列中,并检查它如何与其他受CPU约束的操作一起工作。取决于网络的速度,网络会绑定(bind)更多的CPU和更高的带宽。

然而,一种可扩展的方法很难兼顾良好的连接和良好的连接,力求保持低内存占用空间并最大化性能,但这是很难实现的,而且这是一项艰巨的编程任务。玩得开心! ;)

关于ios - 导入非常大的数据集时的CoreData和RestKit性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17877171/

相关文章:

ios - 获取对当前可见 View Controller 的引用

ios - UIPickerView 显示但不加载数据

java - 背景图片会减慢 Android 应用程序的速度

ios - 如何从 CoreData 检索经度和纬度

ios - MWPhotoBrowser 如何添加旋转照片功能?

ios - 核心数据并从 AnyObject 类型制作 double ? swift

Eclipse (Juno) 在 JSF EL Expression Auto Complete 上挂起

java - 创建一个新线程将对象保存到文件

ios - 核心数据与 SQLite

ios - 如何在核心数据中插入和获取多对多关系实体