I needed to separate integers into 3-digit numbers and looked into the formatted() method of the Decimal type.
Calling the formatted() method of type Decimal 100,000 times each for a random integer gradually degrades performance.
I would like to know why this happens.

import Foundation

/// https://stackoverflow.com/a/56381954
func calculateTime(block : (() -> Void)) {
  let start = DispatchTime.now()
  block()
  let end = DispatchTime.now()
  let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
  let timeInterval = Double(nanoTime) / 1_000_000_000
  print("Time: \(timeInterval) seconds")
}

calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
Time: 0.9492465 seconds
Time: 3.29213125 seconds
Time: 7.988363667 seconds
Time: 15.165178292 seconds
Time: 17.305036583 seconds
Time: 25.0114935 seconds
Time: 35.746310417 seconds
Time: 47.024551125 seconds

推荐答案

虽然马特和马丁·R是正确的,但他们实际上并没有指出罪魁祸首.当您使用"内存对象"调试器时,当函数正在执行时,您将看到这个非常有趣的图形:

enter image description here

因此,函数formatted()导致大量分配,主要是类型NSAutoLocale的对象.

这暗示了进一步的问题:由于判断区域设置需要访问file,而实际读取区域设置的位置,您可能还会遇到非常慢的性能.

因此,如果您也想加快速度,您应该显式地使用预配置的区域设置对象,该对象只分配一次,然后将其用作格式化字符串的参数.

编辑:

为了证明我的假设,我创建了一个等价的声明,并将其与您的原始声明进行了比较:

您的原始代码:

calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }

Time: 9.674371748 seconds

使用单一区域设置的等效代码:

let locale = Locale()
calculateTime { for _ in 0...100_000 { _ = NSDecimalNumber(
    value: Int.random(in: 0...Int.max))
    .description(withLocale: locale)
} }

Time: 0.210493037 seconds

在不做任何进一步修改的情况下,重复调用改进后的语句,您会得到如下结果:

Time: 0.224133942 seconds
Time: 0.238930039 seconds
Time: 0.214735965 seconds
Time: 0.220390686 seconds
Time: 0.212360066 seconds
Time: 0.207630215 seconds
Time: 0.205125154 seconds

...

Swift相关问答推荐

在列表项内的NavigationLink中的按钮无法正常工作

如何在visionOS上删除PhotosPicker背景 colored颜色 ?

在visionOS 1.0中已弃用';base Color';:请改用`Color`属性

如何绑定环境变量ios17

Swift 运算符中 inout 的行为

Observable.create 捕获行为

如何通过 Enum 属性使用新的 #Predicate 宏获取

VisionOS TabBar预览中是否存在漏洞?

为什么自定义串行队列的目标是全局队列时,Swift中不会并发执行?

使用异步收集发布者值

在 RealityKit 中查找特定模型的 findEntity(named:) 方法的替代方法?

如何在 macOS/AppKit 的窗口选项卡上接受拖动项目的放置?

UUID 哈希值是不确定的吗?

供应和普通数组中具有空值的 map 函数的行为不一致?

类型 '()' 不能符合 View (除非它肯定是 View,这次没有恶作剧)

在 xcode 13 中的构建之间保持可访问性权限

将if let与逻辑或运算符一起使用

FCM 后台通知在 iOS 中不起作用

在 Swift 框架中加载资源(例如故事板)

在 Swift 中为 UIPickerView 设置默认值?