JSONSerialization.jsonObject在Swift中的性能

JSONSerialization.jsonObject在Swift中的性能,swift,Swift,我有一个JSON文件(只是一个DICT数组),60兆字节大。在PHP中,解析需要2秒,但在Swift中,解析需要7秒。这太荒谬了。是我做错了什么吗? Swift代码: let json = try! JSONSerialization.jsonObject( with: try! Data( contentsOf: URL( fileURLWithPath: "/some/file/path/to.json" ) ) ) a

我有一个JSON文件(只是一个DICT数组),60兆字节大。在PHP中,解析需要2秒,但在Swift中,解析需要7秒。这太荒谬了。是我做错了什么吗? Swift代码:

let json = try! JSONSerialization.jsonObject(
    with: try! Data(
        contentsOf: URL(
            fileURLWithPath: "/some/file/path/to.json"
        )
    )
) as! [[AnyHashable: Any]]
我简化了代码,使之成为一个操作,但缓慢的部分是JSONSerialization.jsonObject,我显式地测量了它(从文件加载数据的速度与预期一样快)。PHP代码非常简单-
json\u解码(file\u get\u contents())

值得一提的是,在发布模式下构建(带有优化)并没有改善这种情况

UPD:在分析应用程序之后,我发现瓶颈正在将结果转换为[[AnyHashable:Any]],将其更改为[[String:Any]]会稍微改善情况(从7秒到~5.3秒),但这仍然是一种耻辱和痛苦


所以现在的问题基本上是:为什么强制转换速度如此之慢,有没有一种方法可以更快地处理大型JSON对象(或任何其他序列化数据)?

我不会对您用JSON编码60MB进行评判……好吧,我会对您进行一点评判。存储这么多数据的格式太疯狂了。把它从我的系统里弄出来;让我们努力加快速度

首先,你能直接跳到Swift 4吗?如果是这样的话,就摆脱
JSONSerialization
,直接进入新的领域。它避免了许多类型问题。也就是说,它可能更快,也可能不会更快

让我们来回答“为什么施法如此缓慢”的问题。简单。铸造速度很快。你不是演员。你在改变信仰
AnyHashable
是一种类型的橡皮擦;它是一种与字符串完全不同的结构类型:

public struct AnyHashable {
您必须将
字符串
框入
AnyHashable
结构。这实际上相当快(因为“写下即抄”的工作原理),但这意味着这本词典是一本完全不同的词典。你强迫它做一个完整的副本

我过去处理大量JSON数组的方式是手工部分解析它们。扔掉第一个
[
,一次收集一个JSON对象,对其进行解析,然后将结果放入数组中。这样,您就不必将所有数据都放入内存,也不需要消耗600MB的高水位线。如果您对输入JSON有一定的控制权,这种技术显然效果最好。例如,我通常会做一些欺骗,然后编写JSON像这样:

[
    { ... JSON ... },
    { ... JSON ... }
]
这使得解析记录变得非常快速和简单(只需在换行符上拆分)。(我碰巧喜欢这一点,因为它对命令行工具(如grep和awk)非常友好,根本不需要JSON解析)。它仍然是合法的JSON,但有了一点特殊知识,我可以更快地解析它

对于基准测试,我还建议您在ObjC中构建它,以将
NSJSONSerialization
与“将ObjC类型桥接到Swift”分离开来。
NSJSONSerialization
通常被认为是一个相当快的解析器。如果您不十分小心,桥接到Swift的代价会很高(如上所述)。(我喜欢斯威夫特,但这是一种很难解释的语言。)


看起来这个空间里还有一个玩家叫,但我还没试过。(过去有一个非常著名的软件包,名为
JSONKit
,它通过玩ObjC技巧,速度非常快,会让你的皮肤爬行,但令人惊讶的是,它工作得非常好,因此必须原谅。但这些技巧最终赶上了它,我认为它甚至不再工作了。)

我想瓶颈是
数据(<代码> >代码> jsOnjulal.jsObjult<代码>不。从文件加载数据需要0.05s。SWIFTYJSON只是基础JSONSOLISTION的一个糖。在该包中没有优化。使用起来更容易,但肯定慢了。我的目标是性能。哦,是的,我忘了提我在说。关于桌面/服务器计算机。我认为移动设备根本不会解析这个文件,因为Swift在解析它时会消耗多达600兆的RAM。这也很糟糕。转换的缓慢是桥接/转换-
JSONSerialization
必须桥接Objective-C的类型,有效地执行O(n)数据的副本。强制转换到
AnyHashable
会增加一个O(n)将
String
s包装在
AnyHashable
框中时进行复制。如您所见,删除
AnyHashable
转换可以节省大量时间。
JSONDecoder
现在使用
JSONSerialization
,正如您所说的,目前不会更快。也就是说,避免了额外的(n) 将数据复制到
AnyHashable
中的框中肯定会有帮助。好吧,我不选择JSON大小,它可能更大:)是的,它被缩小了,全部放在一行中,所以逐个dict解析dict现在有点棘手(但仍然完全可行)。任何hashable都有好处,我肯定应该去掉它(顺便说一句,JSON只允许字符串作为索引)。JSON规范仅限于
String
索引是正确的,依赖它是很好的。