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

时间:2013-07-26 09:02:15

标签: 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组合中获得最佳性能。

我为你的专业答案感到激动。也许布莱克也可以直接回答我这个问题。

1 个答案:

答案 0 :(得分:11)

嗯,首先,如果你想要最高性能,如果你真的需要那么,不要使用RestKit,不要使用AFNetworking并且不要使用NSJSONSerialization。它们都受到设计选择的影响,这些设计选择在处理大型数据集时效果不佳,并且您的目标是保持适度内存占用量和表现。

您应该拥有一个非常大的单个JSON(可能是一个JSON数组,其元素是JSON对象)作为单个连接的主体,以获得卓越的性能。或者,您可以使用自定义传输格式,在一个连接中发送多个JSON(例如,一系列JSON对象,由"空格&#34分隔开来。)。

拥有大量连接肯定很慢。

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

注意:

当并行执行此操作时,您尤其容易受到连接错误的影响,并且保持一致且逻辑正确的数据集可能会成为一项挑战。因此,如果您的连接质量不佳且频繁中断,您可以先将JSON文件下载并保存到临时文件中(也支持HTTP范围标题,以便有机会暂停和恢复下载)。当然,你的表现会降低 - 但在这种情况下,你无论如何都不能让它变快。

同样,当你的目标是最高性能时,你应该利用所有CPU的功能,这些功能在有意义的情况下并行运行 - 特别是当连接速度很快时。

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

当您收到JSON数据时,您需要" map"这成为一个合适的代表。通常,已知的JSON解析器会创建一个" Foundation表示"。但是,更快的方法是直接从JSON创建最终所需类型的对象。这需要一个" SAX风格的API" - 这基本上是解析器的简化版本,它发送"解析事件"代表或客户 - 例如"得到JSON-Array begin"或者"得到JSON布尔值False"等等以及接收这些事件并自动构造所需对象的自定义代码。

这一切都需要一个JSON解析器,它具有您在NSJSONSerialization中找不到的功能:SAX样式的API,"块解析"或解析输入,这是一系列JSON文档。

为了最大限度地利用CPU,磁盘和网络,您需要划分"任务"进入CPU绑定,I / O绑定的网络绑定操作并创建尽可能多的并且并行运行,因为它对系统是理智的。这些任务基本上都是异步运行,接受输入,处理输入,并产生输出,这是下一个异步任务的输入。第一个任务在完成后通知下一个任务,例如通过完成处理程序(块),并通过参数传递其输出。

处理传入的"块" JSON数据,即解析和创建表示,是一个CPU绑定操作。这通常很快,我不认为通过并发队列在所有可用CPU上分配这些CPU绑定任务是值得的。

处理传入的"块" JSON数据基本上可以用两种方法实现,同样有利有弊:

异步处理部分JSON数据

当你得到一个" chunk"在connection:didReceiveData:中,您可以异步将其安排到不同的队列上进行处理(即解析和创建表示),并在与委托不同的线程上运行。

优点:委托立即返回,从而不会阻塞委托线程,从而最快地读取传入的网络数据和适度小的网络缓冲区。连接在尽可能短的时间内完成。

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

同步处理部分JSON数据

当接收到一大块JSON时,将相对于委托的线程同步调用解析器。

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

缺点: 如果处理速度很慢并且内部网络缓冲区已满,这将增加连接处于活动状态的时间,从而增加连接断开的可能性。

这两种方法都受益于 fast 解析器/表示生成器,并且需要一个可以处理" chunks" JSON作为NSData对象,并在完成表示时异步通知客户端。可选地,它还应具有" SAX风格" API。我知道有两个第三方JSON解析器满足这些要求:

jsonlite

JPJson

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

(披露:我是JPJson的作者)

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

一种可扩展的方法,考虑到糟糕和良好的连接,努力维持低内存占用并最大化性能,但很难实现 - 并且是一项具有挑战性的编程任务。玩得开心! ;)