当前位置: 首页 > 知识库问答 >
问题:

以可变数组为值的Swift字典执行很慢?如何正确优化或构建?

惠洛华
2023-03-14

我正在尝试在Swift中构建一个数据结构,将一个整数映射到一个对象数组(一个以int为键、数组为值的字典)。这些对象非常小,它们只包装了一个UIColor和一个Int。我有两个实现,一个使用Swift数组作为字典的值类型,而另一个使用NSMutableArray作为值类型。我的Objective-C代码运行速度非常快,但我的Swift代码运行速度非常慢。理想情况下,我不想使用NSMutableArray,而是希望将其保留为Swift数组。原因是我正在编写一个算法和性能很重要,我注意到objC_msgSend有一些开销。有人能帮我优化我的Swift代码吗?我做错了什么还是这只是swift将数组视为值类型的副产品?如果是,我想了解为什么值类型在这种情况下表现如此缓慢,我的选择是什么,以及这种情况如何扩展?下面我发布了一个代码片段和由此产生的基准测试:

Swift数组代码:

let numColors = colorCount(filter: filter, colorInfoCount: colorInfo.count)
var colorCountsArray: [Int] = [Int]()
var countToColorMap: [Int:[CountedColor]] = [Int:[CountedColor]](minimumCapacity: capacity)
var topColors = [CountedColor]()

var startTime = CACurrentMediaTime()
for (color, colorCount) in colorInfo {
    colorCountsArray.append(colorCount)
    if countToColorMap[colorCount] != nil {
        countToColorMap[colorCount]?.append(CountedColor(color: color, colorCount: colorCount))
    } else {
        countToColorMap[colorCount] = [CountedColor(color: color, colorCount: colorCount)]
    }
}
var endTime = CACurrentMediaTime()
print("Time after mapping: \(endTime - startTime)")

Swift性能

Time after mapping: 45.0881789259997

NSMutableArray代码:

let numColors = colorCount(filter: filter, colorInfoCount: colorInfo.count)
var colorCountsArray: [Int] = [Int]()
var countToColorMap: [Int:NSMutableArray] = [Int:NSMutableArray](minimumCapacity: capacity)
var topColors = [CountedColor]()


var startTime = CACurrentMediaTime()
for (color, colorCount) in colorInfo {
    colorCountsArray.append(colorCount)
    if countToColorMap[colorCount] != nil {
        countToColorMap[colorCount]?.add(CountedColor(color: color, colorCount: colorCount))
    } else {
        countToColorMap[colorCount] = NSMutableArray(object: CountedColor(color: color, colorCount: colorCount))
    }
}
var endTime = CACurrentMediaTime()
print("Time after mapping: \(endTime - startTime)")

NSMutableArray性能:

Time after mapping: 0.367132211999888

colyInfo对象是将UIColor对象映射到表示计数的整数值的字典。代码本质上是反向映射,将整数映射到UIColor数组(它是一个数组,因为多个颜色可以具有相同的计数)。colyInfo内部有60,000个UIColor、Int键值对。

共有2个答案

全弘深
2023-03-14

在swift 4.2出现之前我有一些工作要做

var countToColorMap = [Int: [CountedColor]]()

for (color, colorCount) in colorInfo {
    countToColorMap[colorCount, default: [CountedColor]()].append(CountedColor(color: color as! UIColor, colorCount: colorCount))
}

它速度快,可读性强

蓟捷
2023-03-14

写时复制是一件棘手的事情,您需要仔细考虑有多少东西共享您试图修改的结构。罪魁祸首在这里。

countToColorMap[colorCount]?.append(CountedColor(color: color as! UIColor, colorCount: colorCount))

这将生成一个临时值,该值将被修改并放回字典中。由于两个“东西”正在查看相同的底层数据结构(字典和append),因此它强制写入副本。

解决这个问题的秘诀是确保修改时只有一个副本。怎么做?把它从字典中拿出来。替换这个:

if countToColorMap[colorCount] != nil {
    countToColorMap[colorCount]?.append(CountedColor(color: color as! UIColor, colorCount: colorCount))
} else {
    countToColorMap[colorCount] = [CountedColor(color: color as! UIColor, colorCount: colorCount)]
}

其运行时为:

Elapsed Time: 74.2517465990022
53217

有了这个:

var countForColor = countToColorMap.removeValue(forKey: colorCount) ?? []
countForColor.append(CountedColor(color: color as! UIColor, colorCount: colorCount))
countToColorMap[colorCount] = countForColor

其运行时为:

Elapsed Time: 0.370953808000195
53217
 类似资料:
  • 问题内容: 我正在尝试在Swift中构建一个数据结构,该数据结构将一个Integer映射到一个对象数组(一个以int为键,而array为值的字典)。这些对象非常小,它们只包装了一个UIColor和一个Int。我有两种实现,一种使用Swift数组作为Dictionary的值类型,而另一种使用NSMutableArray作为值类型。我的Objective- C代码执行得非常快,但是我的Swift代码却

  • 问题内容: 下面的代码将简单的值持有者映射为布尔值,在Java中的运行速度比Swift 2快20倍-XCode 7 beta3,“最快,积极的优化[-Ofast]”和“最快,完整的模块优化”处于打开状态。在Java中,每秒可以进行2.8亿次以上的查询,但是在Swift中,只能达到1000万次。 当我在Instruments中查看它时,我看到大多数时间都在进行与映射查找相关的一对保留/释放调用。关于

  • 问题内容: 我有一本字典,其中包含用枚举值散列的对象: 我希望能够提取此字典包含的所有颜色(值)的数组。我以为我可以使用该属性,就像遍历字典值()一样,但这会返回错误: 似乎该方法返回了一个更抽象的集合类型,而不是返回值的an 。有没有一种方法可以获取包含字典值的而不循环提取它们的值? 问题答案: 从Swift 2.0开始,的属性现在返回而不是。该类型知道如何使用此抽象集合类型进行初始化: Swi

  • 下面的代码将简单的值持有者映射到布尔值,它在Java中的运行速度比Swift2-xCode7Beta3快20倍以上,“最快的、积极的优化[-ofast]”和“快速的、整个模块的优化”已经开启。我在Java中每秒可以得到超过2.8亿次查找,但在Swift中只能得到大约1000万次查找。 当我在Instruments中查看它时,我看到大部分时间都是进入一对与映射查找相关联的retrain/releas

  • 问题内容: 我在Swift中使用可选字典发现了一些令人惊讶的行为。 我已经做了很多事情,试图找出我可能会缺少的东西,但是除了使字典不是可选的以外,似乎没有什么能使此代码正常工作。我想念什么? 我能得到的最接近的是以下内容,但它当然是荒谬的。 问题答案: 灯泡时刻是您意识到可选词典不是词典的时候。可选的东西不是那个东西!这是一个可选的!仅此而已。可选本身是一种类型。Optional只是一个枚举,包装

  • 问题内容: 例如: 字典将包含以下内容: 在Swift中有可能吗? 我是否可以访问像字典这样的类,例如可能使用: 或类似的东西? 谢谢。 问题答案: 您只需将计算属性添加到您的属性中即可返回带有您的值的。请注意,Swift本机字典类型没有任何称为的方法。您需要将您强制转换为: 您还可以按照@ColGraff发布的链接答案中的建议扩展协议,以使其对所有结构通用: