使用大型数据集,Swift数据初始化速度慢,内存效率低

时间:2017-01-19 20:02:32

标签: objective-c swift performance nsdata

如果我尝试使用相对较大的Data初始化Swift MutableRandomAccessSlice<Data>结构,则程序启动会在内存使用中变大,并且需要很长时间才能完成。但是,使用NSData在Objective-C中执行相同的操作似乎没有相同的问题。

例如,使用以下代码:

let startData = Data(count: 100_000_000)
let finalData = Data(startData[0..<95_234_877])

如果我使用以下方法编译它:

xcrun swiftc -O -sdk `xcrun --show-sdk-path --sdk macosx` -o output main.swift

执行(在我的MacBook Air 2011上)需要很长时间才能完成(87秒)并且内存使用量通过屋顶(见下面最多625MB):

$ time ./output
./output  85.21s user 1.29s system 99% cpu 1:26.91 total

$ top -o MEM
PID    COMMAND      %CPU  TIME     #TH   #WQ  #PORT MEM    PURG   CMPRS  PGRP  PPID  STATE
38156  output       99.0  01:25.57 1/1   0    10    625M+  0B     992M+  38156 36025 running

如果我分析每一步,创建startData需要大约0.00015秒,从startData创建切片需要0.000007秒,剩余的时间用于初始化finalData

如果我在Objective-C中做同样的事情:

NSData *startData = [[NSMutableData alloc] initWithLength:100000000];
NSData *finalData = [startData subdataWithRange:NSMakeRange(0, 95234877)];

它只需要大约0.00017秒。

我在Swift示例中做错了什么?两者之间似乎存在很大的差异。

1 个答案:

答案 0 :(得分:1)

如您所见,Objective-C代码[startData subdataWithRange:NSMakeRange(0, 95234877)]相当于startData.subdata(in: 0..<95_234_877)

当您撰写Data(startData[0..<95_234_877])时,Swift会调用public convenience init<S : Sequence where S.Iterator.Element == Iterator.Element>(_ elements: S)的{​​{1}},它在RangeReplaceableCollection.swift.gyb中定义。实施的核心部分是这样的:

RangeReplaceableCollection

您知道对集合重复for element in newElements { append(element) } 可能效率低下。

并且,如果您要从append初始化Data,则最好调用特定于[UInt8]的初始值设定项:

[UInt8]

let data = Data(bytes: [UInt8](repeating: 0, count: 10_000_000)) 调用上面提到的Data([UInt8](repeating: 0, count: 100_000_000))中的初始值设定项。

在我看来,Swift应该更多地优化这种默认实现,但很难使它们像特定于类型的操作一样高效。