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

Fab*_*b1n 5 performance core-data ios restkit

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

SO上有几个问题指向同一个方向:

使用CoreData在iPhone上导入大型数据集

但我的问题仍然是另一个问题,因为我知道,如果JSON文件太大,我必须把它切成块.我会去做的!

如何使用RestKit中的CoreData完成导入.
似乎存在父/子上下文设置,在最短的时间内导入大型数据集效率非常(可能在启动时一次全部导入 - 无批量/延迟导入!!!).

请参阅此处Florian Kugler关于CoreData(Stacks)中性能导入的帖子

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

我真的想与CoreData坚持而没有切换到普通的SQLite,获得最有可能表现出来的组合CoreDataRestKit.

我很高兴你的专业答案.也许布莱克也可以直接回答我这个问题.

Cou*_*per 11

好吧,首先,如果你想要最高性能,如果你真的需要,不要使用RestKit,不要使用AFNetworking而不要使用NSJSONSerialization.他们都从设计选择与处理时不踢好遭受的数据集,如果你的目标是维持适度内存占用和较高的性能.

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

拥有大量连接肯定很慢.

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

注意:

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

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

JSON解析器还应该能够解析NSData对象中包含的"块" - 即部分JSON - 因为这是我们得到的connection:didReceiveData:.

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

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

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

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

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

异步处理部分JSON数据

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

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

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

同步处理部分JSON数据

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

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

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

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

jsonlite 和这个

JPJson

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

(披露:我是JPJson的作者)

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

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