内容简介:1.之前在一些性能优化的文章2.很多同学可能只是跟我之前一样,只是知道这个方法比较耗时,但是对于进行缓存优化后的效果对比并不清楚,所以自己写了一个小Demo,对优化前后进行一些性能测试,方便大家参考,也方便大家在项目中使用执行时间统计:
1.之前在一些性能优化的文章 《性能优化之NSDateFormatter 》 中,看到有提到“创建DateFormatter开销会比较大”,也有的文章 《(多帖总结) iOS性能优化技巧》 里面说是“设置日期格式”这个方法较为耗时,但实际上测试发现是“生成字符串”这个方法较为耗时,所以我觉得可以纠正一些这些说法
let formatter = DateFormatter()//创建DateFormatter实例对象 formatter.dateFormat = "yyyy年MM月dd日"//设置日期格式 string = formatter.string(from: date)//生成字符串 复制代码
2.很多同学可能只是跟我之前一样,只是知道这个方法比较耗时,但是对于进行缓存优化后的效果对比并不清楚,所以自己写了一个小Demo,对优化前后进行一些性能测试,方便大家参考,也方便大家在项目中使用
运行时间对比
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() testInOldWay(1) testInNewWay(1) testInOldWay(10) testInNewWay(10) testInOldWay(100) testInNewWay(100) testInOldWay(1000) testInNewWay(1000) testInOldWay(10000) testInNewWay(10000) testInOldWay(100000) testInNewWay(100000) testInOldWay(1000000) testInNewWay(1000000) } //不进行缓存 func testInOldWay(_ times: Int) { var string = "" let date = Date.init() let startTime = CFAbsoluteTimeGetCurrent(); for _ in 0..<times { let formatter = DateFormatter() formatter.dateFormat = "yyyy年MM月dd日" string = formatter.string(from: date) } let duration = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0; print("使用oldWay计算\n\(times)次,总耗时\n\(duration) ms\n") } //进行缓存 func testInNewWay(_ times: Int) { var string = "" let date = Date.init() let startTime = CFAbsoluteTimeGetCurrent(); for _ in 0..<times { string = DateFormatterCache.shared.dateFormatterOne.string(from: date) } let duration = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0; print("使用newWay计算\n\(times)次,总耗时\n\(duration) ms\n") } } //创建单例进行缓存 class DateFormatterCache { //使用方法 //let timeStr = DateFormatterCache.shared.dateFormatterOne.string(from: publishTime) static let shared = DateFormatterCache.init() lazy var dateFormatterOne: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy年MM月dd日" return formatter }() lazy var dateFormatterTwo: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .full formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z" formatter.locale = Locale.init(identifier: "en_US") return formatter }() } 复制代码
日志输出
使用oldWay计算 1次,总耗时 7.187008857727051 ms 使用newWay计算 1次,总耗时 0.1609325408935547 ms 使用oldWay计算 10次,总耗时 0.552058219909668 ms 使用newWay计算 10次,总耗时 0.05888938903808594 ms 使用oldWay计算 100次,总耗时 4.320979118347168 ms 使用newWay计算 100次,总耗时 0.6080865859985352 ms 使用oldWay计算 1000次,总耗时 47.60599136352539 ms 使用newWay计算 1000次,总耗时 5.526900291442871 ms 使用oldWay计算 10000次,总耗时 427.8249740600586 ms 使用newWay计算 10000次,总耗时 45.81403732299805 ms 使用oldWay计算 100000次,总耗时 4123.620986938477 ms 使用newWay计算 100000次,总耗时 459.98501777648926 ms 使用oldWay计算 1000000次,总耗时 40522.77398109436 ms 使用newWay计算 1000000次,总耗时 4625.54395198822 ms 复制代码
执行时间统计:
在测试中,我们发现执行一次formatter的创建和设置日期格式需要7.187008857727051 ms,执行10次却只需要0.552058219909668 ms,这是因为第一次执行 let formatter = DateFormatter()
这行代码时可能会涉及到DateFormatter类相关的一些初始资源的初始化,而后续执行十次时已经不包含这一过程所需要的耗时,所以看上去执行一次的时间反而长一些,我们在计算性能比较时可以通过增加执行次数,来忽略这些因素的影响,当我们执行1000000次时,不进行缓存使用oldWay计算需要40522.77398109436 ms,而一次初始化的开销最大为第一次的执行的耗时7.187008857727051 ms,
7.18/40522.77 = 0.0177% 复制代码
占比为0.0177,这些因素的影响已经降低为万分之一了,所以我们可以将执行1000000次时,不使用缓存和使用缓存的执行一次所需平均时间方法耗时
不使用缓存(oldWay,每次创建DateFormatter对象并且设置格式) 执行一次耗时:40.52 us 使用缓存(oldWay,每次创建DateFormatter对象并且设置格式) 执行一次耗时:4.625 us 使用缓存的方案的执行时间大概是不使用缓存的方案的时间的11.4% 复制代码
究竟是创建DateFormatter对象耗时还是设置日期格式耗时?
func testPartInOldWay(_ times: Int) { var string = "" let date = Date.init() var startTime1: CFAbsoluteTime = 0; var startTime2: CFAbsoluteTime = 0; var startTime3: CFAbsoluteTime = 0; var startTime4: CFAbsoluteTime = 0; var duration1: CFAbsoluteTime = 0; var duration2: CFAbsoluteTime = 0; var duration3: CFAbsoluteTime = 0; for i in 0..<times { startTime1 = CFAbsoluteTimeGetCurrent(); let formatter = DateFormatter() startTime2 = CFAbsoluteTimeGetCurrent(); formatter.dateFormat = "yyyy年MM月dd日" startTime3 = CFAbsoluteTimeGetCurrent(); string = formatter.string(from: date) startTime4 = CFAbsoluteTimeGetCurrent(); duration1 += (startTime2 - startTime1) * 1000.0; duration2 += (startTime3 - startTime2) * 1000.0; duration3 += (startTime4 - startTime3) * 1000.0; } print("创建DateFormatter对象耗时=\(duration1)ms\n设置日期格式耗时=\(duration2)ms\n生成字符串耗时=\(duration3)ms\n\n") } 复制代码
输出结果:
执行1次 创建DateFormatter对象耗时=0.030994415283203125ms 设置日期格式耗时=0.3859996795654297ms 生成字符串耗时=1.6570091247558594ms 执行10次 创建DateFormatter对象耗时=0.019073486328125ms 设置日期格式耗时=0.012159347534179688ms 生成字符串耗时=0.5759000778198242ms 执行100次 创建DateFormatter对象耗时=0.0768899917602539ms 设置日期格式耗时=0.06973743438720703ms 生成字符串耗时=4.322528839111328ms 执行1000次 创建DateFormatter对象耗时=0.7123947143554688ms 设置日期格式耗时=0.702977180480957ms 生成字符串耗时=41.77117347717285ms 执行10000次 创建DateFormatter对象耗时=6.549596786499023ms 设置日期格式耗时=5.913138389587402ms 生成字符串耗时=370.6216812133789ms 执行100000次 创建DateFormatter对象耗时=65.13833999633789ms 设置日期格式耗时=59.78119373321533ms 生成字符串耗时=3586.0002040863037ms 执行1000000次 创建DateFormatter对象耗时=661.7592573165894ms 设置日期格式耗时=575.5696296691895ms 生成字符串耗时=35309.07988548279ms 复制代码
可以从输出结果中发现是 string = formatter.string(from: date)
这行代码耗费时间最多,所以主要耗时并不在于执行DateFormatter.init()和formatter.dateFormat = "yyyy年MM月dd日",在对我们项目使用Instrument进行分析时,测试结果也证明了这一点
测试环境:iPhone 7
测试系统:iOS 12.1(16B92)
app启动后的60s内,快速滑动feed流页面,在这一过程中,主线程的执行时间大概是10.59s,我们项目中日期处理主要在 func detailString(date: Date) -> String
这个方法中进行,这个方法的运行时间为730ms,而其中 timeStr = formatter.string(from: date)
这行代码的运行时间为628ms,所以也说明了生成日期字符串的方法耗时较多。
在项目中的实际提升
测试环境:iPhone 7
测试系统:iOS 12.1(16B92)
测试时间:app启动后的60s
测试步骤:使用Instruments的Time Profiler启动app,在启动后的60s内,快速滑动列表页。
没有对DateFormatter进行缓存时:
在我们项目中,detailString方法每次调用时会创建DateFormatter,生成日期字符串
let formatter = DateFormatter() formatter.dateFormat = "MM月dd日" timeStr = formatter.string(from: date) 复制代码
测试结果:
app启动后的60s内,主线程执行时间10.59s,detailString的执行730ms
对DateFormatter进行缓存后:
timeStr = DateFormatterCache.shared.dateFormatterOne.string(from: date) class DateFormatterCache { //使用方法 //let timeStr = DateFormatterCache.shared.dateFormatterOne.string(from: publishTime) static let shared = DateFormatterCache.init() lazy var dateFormatterOne: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "MM月dd日" return formatter }() 复制代码
我们通过DateFormatterCache的单例对象shared来获取dateFormatterOne
测试结果:
app启动后的60s内,主线程执行时间10.58s,detailString的执行76ms
从执行时间上对比,缓存后,执行时间是之前的10.4%,对性能的提升还是比较大的
最后
Demo在这里https://github.com/577528249/SwiftDemo/tree/master/DateFormatterDemo
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 性能优化第一课:性能指标
- 【前端性能优化】vue性能优化
- Golang 性能测试 (2) 性能分析
- 【前端性能优化】02--vue性能优化
- Java性能 -- 性能调优标准
- Java性能 -- 性能调优策略
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
用户故事与敏捷方法
Mike Cohn / 石永超、张博超 / 清华大学出版社 / 2010-4 / 39.00元
《用户故事与敏捷方法》详细介绍了用户故事与敏捷开发方法的结合,诠释了用户故事的重要价值,用户故事的实践过程,良好用户故事编写准则,如何搜集和整理用户故事,如何排列用户故事的优先级,进而澄清真正适合用户需求的、有价值的功能需求。 《用户故事与敏捷方法》对于软件开发人员、测试人员、需求分析师和管理者,具有实际的指导意义和重要的参考价值。一起来看看 《用户故事与敏捷方法》 这本书的介绍吧!