如何解决为什么first.splitseparator:“”.map {IntString$ 0!}优于first.splitseparator:“”.map {Int$ 0!}?
import Foundation
let first = readLine()! // input : 10 20 30
processtime {
first.split(separator: " ").map { Int($0)! }
}
processtime {
first.split(separator: " ").map { Int(String($0))! }
}
func processtime(blockFunction: () -> ()) {
let startTime = CFAbsoluteTimeGetCurrent()
blockFunction()
let processtime = CFAbsoluteTimeGetCurrent() - startTime
print("performance = \(processtime)")
}
性能= 0.0012700557708740234 =>整数($ 0)!
performance = 0.000843048095703125 => Int(String($ 0))!
我使用map转换为Int。但是,将它转换为“ Int(String($ 0))!”所花的时间更少。我不知道为什么。
解决方法
split
不返回字符串,而是子字符串,因此Int($0)
表示将子字符串转换为整数,而Int(String($0))
则将子字符串转换为字符串,然后转换为整数
查看这两种格式的反汇编,它们正在调用不同的Int.init?
方法。但是组装中有很多事情要做,所以很难说这是否是唯一的区别,或者在后台进行的其他一些事情是否也会产生适度的影响。
但是,可以肯定地说,将String
转换为Int
比处理子字符串更有效。话虽这么说,我会坚持使用更简洁的代码,而不用担心这种微不足道的差异,除非这种差异(以千分之一秒为单位)将变得很重要(即,您正在执行数百万次,不是代码中其他地方可能具有更多实质性优化机会的其他内容等)。正如Donald Knuth所说:
我们应该忘记效率低下的问题,例如大约97%的时间:过早的优化是万恶之源。然而,我们不应该放弃我们那关键的3%的机会。
顺便说一句,在衡量效果时,而不是衡量单个呼叫时,要进行数百万次,并观察它们之间的比较。另外,在测试性能时,您可能还希望随机化测试顺序,重复执行几次,以确保执行顺序不会影响性能。最后,请确保您正在测试优化的发行版而不是调试版。
此外,单元测试还有一种measure
方法来比较性能,重复测试十次:
class ConversionBenchmarkTests: XCTestCase {
let input = "10 20 30"
let count = 100_000
func testInt() throws {
measure {
for _ in 0 ..< count {
let result = input.split(separator: " ").map { Int($0)! }
XCTAssertEqual(result.count,3)
}
}
}
func testString() throws {
measure {
for _ in 0 ..< count {
let result = input.split(separator: " ").map { Int(String($0))! }
XCTAssertEqual(result.count,3)
}
}
}
}
String
再现速度快一倍:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。