swift - 性能:Array.removeAll vs `= []`
问题描述
Array
Swift /Dictionary
原始函数之间在计算removeAll
和/或内存方面的性能是否存在差异init
?基本上,我在问,在 Swift 中重置可变集合的优缺点是什么,是否被认为是清空Array
/的推荐方法Dictionary
?
// Scenario A
var myArray = ["one", "two", "three"]
myArray.removeAll()
// Scenario B
myArray = ["one", "two", "three"]
myArray = []
解决方案
性能差异不应该是显着的,因为它们在很大程度上做同样的事情。让我们看一下源代码:
/// Removes all elements from the array.
///
/// - Parameter keepCapacity: Pass `true` to keep the existing capacity of
/// the array after removing its elements. The default value is
/// `false`.
///
/// - Complexity: O(*n*), where *n* is the length of the array.
@inlinable
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
if !keepCapacity {
_buffer = _Buffer()
}
else {
self.replaceSubrange(indices, with: EmptyCollection())
}
}
对于不同的类型,此方法还有其他几种实现,但模式始终相同。如果removeAll
参数keepCapacity
是false
,只需重新初始化它,很大程度上相当于说myArray = []
。
因此,唯一的问题是您是否要在删除其元素后保留数组的容量(如果您要清空一个大数组并准备用另一个相同大小的数组重新填充,您可能会这样做)。
如果您愿意,请对其进行基准测试。例如,将“单元测试”目标添加到您的项目中,将迭代次数提高到足以使持续时间可观察到:
class MyAppTests: XCTestCase {
func testPerformanceRemoveAll() {
var countTotal = 0
var myArray: [Int] = []
self.measure {
for _ in 0 ..< 1_000_000 {
myArray = Array(repeating: 0, count: 1_000)
myArray.removeAll(keepingCapacity: false)
countTotal += myArray.count
}
}
XCTAssertEqual(countTotal, 0)
}
func testPerformanceReinitialize() {
var countTotal = 0
var myArray: [Int] = []
self.measure {
for _ in 0 ..< 1_000_000 {
myArray = Array(repeating: 0, count: 1_000)
myArray = []
countTotal += myArray.count
}
}
XCTAssertEqual(countTotal, 0)
}
}
结果如下:
Test Case '-[MyAppTests.MyAppTests testPerformanceReinitialize]' started.
/.../MyApp/MyAppTests/MyAppTests.swift:41: Test Case '-[MyAppTests.MyAppTests testPerformanceReinitialize]' measured [Time, seconds] average: 0.221, relative standard deviation: 6.559%, values: [0.264467, 0.216076, 0.216146, 0.216040, 0.216014, 0.216426, 0.216374, 0.215876, 0.216272, 0.216152], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[MyAppTests.MyAppTests testPerformanceReinitialize]' passed (2.646 seconds).
Test Case '-[MyAppTests.MyAppTests testPerformanceRemoveAll]' started.
/.../MyApp/MyAppTests/MyAppTests.swift:26: Test Case '-[MyAppTests.MyAppTests testPerformanceRemoveAll]' measured [Time, seconds] average: 0.235, relative standard deviation: 6.712%, values: [0.282223, 0.229732, 0.229601, 0.229624, 0.229584, 0.229652, 0.229695, 0.229729, 0.229702, 0.229659], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[MyAppTests.MyAppTests testPerformanceRemoveAll]' passed (2.602 seconds).
顺便说一句,如果您想知道为什么我在清空数组后添加总数,我只是想确保在清空数组后我实际使用了数组,以确保优化器不会优化进行清空的代码。在这种情况下没有必要,但要谨慎。
我也用Int
代替 进行了测试String
,因为我对String
开销并不好奇,而是试图专注于Array
行为。
最重要的是,性能差异在很大程度上无法区分。
推荐阅读
- c# - 在 ASP.NET 网络表单中使用 SqlDependency
- javascript - 如果多个选择器被禁用,jQuery 返回 true
- google-apps-script - GAS Web 应用程序表单到电子表格不会自行更新
- python - 使用 pygame (python) 播放声音
- java - 为什么我的服务在媒体播放器循环时被破坏?
- c# - Azure 应用服务不会从 appsettings.Staging.json 获取配置键/值
- html - 确保弹出对话框在用户页面位置的任何地方弹出?
- selenium - 在 Selenium Header 中覆盖和发送数据
- automation - 如何自动从 MS Teams 下载文件并将它们上传到 Erido?
- javascript - 制作 HTML form.submit() 时如何禁用浏览器转到上一页?