我正在使用dictionary
在Swift中进行项目。
此词典的类型为[String : [Posting]]
。我要在其中插入大约200k个不同的“术语”(键),对于每个术语,我要在列表中附加大约500至1000个对象。我知道这是一种奇怪的做法,但我没有选择,我必须处理所有这些要素。
问题在于,随着字典的变大,这非常慢。我尝试过切换到NSMutableDictionary
,但不走运。
每次需要插入元素时,都会调用我的addTerm
函数:
func addTerm(_ term: String, withId id: Int, atPosition position: Int) {
if self.map[term] == nil {
self.map[term] = [Posting]()
}
if self.map[term]!.last?.documentId == id {
self.map[term]!.last?.addPosition(position)
}
else {
self.map[term]!.append(Posting(withId: id, atPosition: position, forTerm: term))
}
}
编辑:我意识到不是导致所有这种滞后的字典,而是实际上包含的数组。数组在添加新元素时会过多地重新分配,而我最好的办法是将它们替换为ContiguousArray
。
答案 0 :(得分:1)
当代码太慢时,通常的方法是在Instruments中对其进行概要分析,以找出哪些行实际花费的时间最长并从那里开始。在其他地方可能会遇到瓶颈,等等。直接从Xcode内部运行应用程序还会创建一个调试版本,这会牺牲可调试性的性能。发布版本的性能可能会好得多。
此外,如果您的程序占用大量内存,则系统可能难以使该内存可供您的应用使用。在非iOS平台上,这将导致将内存换出到磁盘,这将严重影响应用程序的性能,因为系统无法预期,接下来将访问字典的哪些元素。
如果内存需求不是造成速度下降的原因,则可以尝试以下几种方法:
如果可以估计要插入字典中的项目数,则可以使用dictionary.reserveCapacity(numberOfItems)
。随着字典的增长,可能需要调整其大小,这可能需要重建哈希表,字典类型在内部使用该哈希表。这种方法也适用于数组。
Swift提供了使用公用键Dictionary(grouping: collection, by: { item in item.property })
将项目自动分组为字典的方法。这种方法的计算效率更高,因为所有内容都可以在一批中处理。
另一种方法可能是使用不需要频繁重新分配的其他数据类型,例如树形图。但是Swift在标准库中没有提供这种类型。
答案 1 :(得分:1)
这是相当普遍的性能陷阱,也可以在以下情况中看到
问题源于以下事实:您在表达式self.map[term]!.append(...)
中进行突变的数组是字典存储中基础数组的临时可变副本。这意味着该数组永远不会被唯一引用,因此总是要重新分配其缓冲区。
这种情况将在Swift 5中通过非官方引入通用访问器来解决,但在此之前,一种解决方案(如上述两个问答中所述)是使用Dictionary
的{{1}} Swift 4.1可以直接在存储中更改值。
尽管您的案例并不是应用单个突变的简单案例,所以您需要某种包装函数才能使您能够对可变数组进行范围化访问。
例如,它看起来像:
subscript(_:default:)
答案 2 :(得分:0)
我有同样的问题。 20万个条目太疯狂了…… 所以我做了一个课,把数组放在那里……
class MyIndex
{
var entries: [Posting]
}
var map = [String: MyIndex]()
现在看来工作很快