2024-09-09T07:39:28.png

DDLoggerSwift是之前为了方便日志调试,封装的iOS工具。比print多了调用行数的日志输出和数据保存。最近碰到在一些效率问题,重新进行了优化调整,发布了5.1.0版本。

整体下来,连续输出一万次,和print一样,保持在1.2秒左右🎉🎉

1、队列管理

日志输入可能是分布在多线程中,如果高频插入数据,或者多个线程。要保证顺序,否则查看日志的时候,顺序错乱,对日志分析更加麻烦。

在考虑效率时,每种方法都有其适用场景和权衡:

1. 串行队列 (Serial Queue)

  • 效率:串行队列会一个任务接一个任务地执行,确保按顺序插入。
  • 优点:实现简单,天然保证顺序。
  • 缺点:性能不高,所有任务必须按顺序执行,无法利用并发优势。
  • 适用场景:日志插入频率较低,顺序性要求较高时使用。

2. DispatchQueue + .barrier

  • 效率:.barrier 允许其他任务在插入操作之外并发执行,直到插入任务需要执行时,会阻塞其他任务,确保该插入操作的独占性。
  • 优点:能够利用并发的优势,在不涉及插入的任务上提升性能。
  • 缺点:当频繁使用 .barrier 时,插入任务可能成为性能瓶颈,因为它会暂停其他任务。
  • 适用场景:需要保证数据顺序,同时想利用并发处理其他任务时使用。

3. OperationQueue + 依赖

  • 效率:OperationQueue 可以灵活控制并发度,可以串行执行或并发执行。通过设置依赖,可以确保任务按顺序完成。
  • 优点:操作灵活,既可以控制顺序,也可以动态调整并发度。
  • 缺点:依赖管理可能增加复杂度,创建和管理 Operation 相对有些开销。
  • 适用场景:需要灵活管理并发度且顺序插入的场景。

4. 时间戳排序 + 并发

  • 效率:这种方式能最大限度利用并发的优势。任务并发执行后,基于时间戳排序,插入操作本身是线程安全的,但排序操作可能会带来额外的开销。
  • 优点:能够充分利用并发处理任务,适合高并发环境。插入顺序由排序决定,不需要阻塞其他任务。
  • 缺点:需要手动维护排序,适合高并发场景,排序可能成为瓶颈,尤其在大量数据插入时。
  • 适用场景:高并发下,插入顺序相对不那么严格,但最终排序时要求一致性。

DDLoggerSwift使用了第二种方案,因为日志是一直产出的,并不知道何时结束,并且用户可能随时关闭APP离开,所以如果去排序插入的时间点不好确定。

TableView的日志刷新

TableView适合数据量较大的展示,虽然使用比较麻烦,但是考虑到拓展性,日志的查看采用TableView,而不是TextView,防止日志量太多时页面加载问题。

barrier排序的缺点就如同上面说的,它会暂停其他任务,在之前版本,考虑开着日志查看也可以动态刷新TableView,但是因为日志插入可能是多个不同线程,特别是网络请求。这就要导致插入一条数据,就需要使用DispatchQueue.main.async切回主线程刷新一下TableView。数据量小的话没问题,但是频繁大数据的话,频繁切换就造成了瓶颈。

issues/7中有人就提到了这个bug,当时使用了throttleTime延迟再刷新的方案,现在思考之后,通过产品思维来优化技术思维。将日志插入和日志展示分成两部分。插入不刷新TableView,这样就避免了主线程切换问题。而在TableView上面添加刷新按钮,点击时取最新数据,因为本身就在主线程上,所以也不需要切换线程。

为了方便展示,在5.1.1版本中,增加了maxPageSize分页设置,默认为10000。当为0时,对数据不进行分页。这样如果数据量小,打开tabview时展示当天全部日志。如果数据量大,可以设置该值进行分页,这样就避免一次性取太多日志,导致打开时卡顿。

数据库批量写入

采用了Sqlite数据库,虽然写入已经很快,但是可以通过批量写入达到更高的性能。考虑到日志的高频写入,所以判断如果数量大于1,就采用批量插入的方式。如果还是一个,就采用单个插入,避免数据库插入事务的消耗。

为了配合这个改变,所以5.1.1版本修改了插入,改为插入数组方式_writeDB(logs: [DDLoggerSwiftItem]),并且修改throttleTime的用途,本来是用作刷新TableView,现在修改为存入缓存列表,之后批量写入数据库,从而提高数据库的写入性能。

其他优化

修改Date格式化

之前Date采用yyyy-MM-dd的DateFormatter,现在修改为iOS系统的dateFormatterISO8601,全局维护该对象,避免了频繁初始化创建的消耗,并且日期转换更加高效。

索引优化

之前维护了mDisplayLogDataArraymDisplayLogIndexArray,用于保存关键词筛选时的索引,实现搜索的关键词cell。现在不需要在日志写入时维护TableView的数据源,打开可以通过Sqlite去维护,所以去掉自己的索引。使用Sqlite自带的索引,从而加快搜索的效率。

Sqlite语法优化

通过对Sqlite的语法优化,特别对Where的查询和字符的插入进行了优化。语义更清晰。


☟☟可点击下方广告支持一下☟☟

最后修改:2024 年 09 月 09 日
请我喝杯可乐,请随意打赏: ☞已打赏列表