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

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

在这个问题上,有几个问题指向了同样的方向:

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

但是我的问题还是不同的,因为我知道,如果JSON文件变得太大,我不得不把它切成块。 我会去做!

在RestKit中用CoreData完成的导入究竟如何?
似乎有一个父/子上下文设置,这是非常低效的,当在最短的时间内导入大数据集 (可能一次启动 – 没有批次/懒惰导入!!! )。

在这里看到一个来自Florian Kugler的在CoreData(Stacks)

我的问题是:我可以设置一个不同的上下文,除了父/子上下文设置已经与RestKit和运行RKManagedObjectRequestOperation导入完全asynchronous和另一个上下文。 然后将上下文合并到mainContext中以获取…

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

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

那么,首先,如果你想要最大的性能,如果你真的需要 ,不要使用RestKit,不要使用AFNetworking,也不要使用NSJSONSerialization 。 它们都受到deviseselect的困扰,处理大型数据集的时候效果不佳,而且您的目标是保持适中的内存足迹和高性能。

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

拥有大量的连接肯定是缓慢的。

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

注意:

当所有这些都是平行进行的时候,你对连接错误特别容易受到攻击,保持一致和逻辑正确的数据集可能成为一个挑战。 因此,如果您的连接遭受质量差和频繁中断,您可能首先下载并保存JSON文件到一个临时文件(也支持HTTP范围标题的机会暂停和恢复下载)。 当然,你的performance会下降 – 但在这种情况下,无论如何你都无法做到这一点。

所以,当你的目标是最高性能的时候,你应该利用所有CPU的能力,并行运行,因为它是有意义的 – 当连接速度很快的时候尤其如此。

JSONparsing器也应该能够parsing包含在一个NSData对象中的“块”(部分JSON),因为这是我们从connection:didReceiveData:获得的connection:didReceiveData:

当您收到JSON数据时,您需要将其“映射”为合适的表示forms。 通常,已知的JSONparsing器创build一个“基础表示”。 但是,更快的方法是直接从JSON中创build最终所需types的对象。 这需要一个“SAX风格的API” – 这基本上是一个parsing器的简化版本,它向委托或客户端发送“parsing事件”,例如“得到JSON-Array开始”或“得到JSON布尔假”等,自定义代码,它接收这些事件并即时构build所需的对象。

这一切都需要一个具有在NSJSONSerialization找不到的function的JSONparsing器:SAX风格的API,“块parsing”或parsinginput,这是一系列JSON文档。

为了最大限度地利用CPU,磁盘和networking,可以将“任务”划分为CPU绑定,I / O绑定和networking绑定操作,并创build尽可能多的并且以并行方式运行。 这些任务基本上都是asynchronous运行,接受input,处理input,并产生一个输出,它是下一个asynchronous任务的input。 第一个任务在完成时通知下一个任务,例如通过完成处理程序(块),并通过parameter passing它的输出。

处理JSON数据的传入“块”,即parsing和创build表示 ,是一个CPU绑定操作。 然而,这通常是相当快的,我不认为通过并发队列来分配所有可用的CPU上的CPU限制任务是不值得的。

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

部分JSON数据asynchronous处理

当你在connection:didReceiveData:得到一个“块”时connection:didReceiveData:你可以asynchronous调度到一个不同的队列上进行处理(即parsing和创build表示),而不是在委托上运行。

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

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

同步处理部分JSON数据

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

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

缺点:如果处理速度慢,内部networking缓冲区变满,则会增加连接活动的时间,从而增加连接断开的可能性。

这两种方法都从一个快速的parsing器/表示生成器中受益,并且需要一个可以将JSON的“块”处理为NSData对象的parsing器,并在完成表示时asynchronous通知客户端。 可选地,它也应该具有“SAX风格”API。 有两个第三方的JSONparsing器,我知道满足这些要求:

jsonlite和这个

JPJson

两者都非常快(比JSONKit和NSJSONSerialization更快),支持SAX风格parsing,并可以将JSON作为NSData对象处理。 JPJson还可以处理包含多个JSON的文件。

(披露:我是JPJson的作者)

创build表示时,下一步是创build并初始化托pipe对象(除非parsing器直接生成pipe理对象),并将对象保存到持久性存储中。 这是一个I / O和CPU绑定操作 – 但是当使用SSD存储时可能会有更多的CPU绑定。 我会安排这个过程到一个单独的队列,并检查它是如何与其他CPU绑定操作一起工作的。 networking的速度取决于networking的速度,networking在更高的带宽下变得更加CPU绑定。

考虑到糟糕和良好的连接的可扩展的方法,努力保持低内存足迹和最大化性能,但是很难实现 – 而且是一个具有挑战性的编程任务。 玩的开心! ;)