Ⅰ Xcode 构建速度优化(一)衡量编译时间
随着项目不断迭代,工程文件越来越多,引用的三方库也越来越多,这些直接导致编译时间的不断增加,完整编译一次项目动辄需要五分钟以上时间,实在有些影响开发效率,是时候来一波提速了。
为编译和构建提速,首先我们需要对速度有一个衡量标准:准确获得构建用时
首先,我们需要定义要衡量和优化的内容。 有两种选择:
xcode默认情况下会跟踪所有构建,我们可以通过更改xcode相关设置,来在活动查看器中显示出构建时间,通过命令行:
每次编译成功后,会在Successed之后显示出所用时间:
Xcode Build Timing Summary是Xcode10中加入的用于查看获取构建时间和发现用时瓶颈方面的最有利工具。 可以通过Proct->Perform Action->Build With Timing Summary来开启:这样在 Build Log 的末尾就会添加 Timing Summary Log。我们可以通过这个 log 看到哪个阶段是耗时的,便于我们进行优化。
如上图中: xib阶段的编译耗时明显是比普通c文件要多的,意味着我们可以通过减少xib方式来优化提升速度
而c文件的编译用时比总时间还要长,是因为c文件是并行编译的
在命令行中同样可以开启这个功能:
常用的第三方工具有 BuildTimeAnalyzer 、 xcode-build-times-rendering 、 XCLogParser 。
BuildTimeAnalyzer可以统计可以得出某个文件的类型检查时长,每个表达式的类型检查时长。
xcode-build-times-rendering是一个Ruby编写的第三方工具,可以方便地分别测量目标的构建时间并在图表上显示它们,使用gem安装
接下来使用这个工具自带命令配置项目
然后构建项目并生成报告:
这个工具使用上比较简单,缺点是只能从宏观上生成各个target编译的整体图标,无法详细列出各个内部编译明细
XCLogParser可以详细列出各个Target和内部每个文件的编译耗时,对我们分析编译时间瓶颈非常有帮助,它的工作原理主要是做为解析器,通过解析xcode编译生成的xcactivitylog日志来记录
安装:
编译项目后,进行安装
安装成功后通过命令:
会自动在当前目录的 build/xclogparser/reports/ 路径下生成报告,其中--project参数需要设置为待分析项目的名字,并注意当前在终端切换到希望写入日志的目录。
报告截图:
这个工具将作为我们后面分析提升编译构建速度的主要使用工具。
经过我多次在不同时间段,不同电脑上不断尝试编译,
我发现编译耗时是一个比较玄的东西,及时在同一台电脑,同一个项目, 同一套环境配置下,编译用时也会随着电脑当前状态(包括同时打开进程、散热等等)上下大幅跳动,就像算法时间复杂度一样,有时候我们明明做了一些细微的优化,但是结果反而是编译耗时增加了,这是很正常的事情
所以,衡量这个标准需要我们取多次试验中的平均值作为参考。
Ⅱ 一个超大数(比如10的20次方),求它的约数个数,要求用最快的方法,编译运行时间不超过一秒!!
重写写了个java算法,效率很理想。
不过long只能支持到10的18次方
运行环境:E8400 + 4G RAM + JDK 1.5 + XP SP3(公司的机子就是牛啊!!!!)
import java.util.ArrayList;
import java.util.List;
public class Submultiple {
public static void main(String args[]){
long start = System.currentTimeMillis();
int[] primeNumAry = new int[64];
get64PrimeNumber(primeNumAry);
long num = 1000000000000000000L;
long orgNum = num;
int facCount = 0;
List<Integer> list = new ArrayList<Integer>();
for(int index = 0, factor = primeNumAry[index]; num != 1; ){
if(num % factor == 0){
facCount++;
num = num /factor;
if(num == 1){
list.add(facCount);
}
continue;
}else{
list.add(facCount);
factor = primeNumAry[++index];
facCount = 0;
}
}
long totalCount = 1L;
for(int item: list){
totalCount *= (item + 1);
}
long end = System.currentTimeMillis();
System.out.println("For number " + orgNum + ", Total " + (end - start)
+ " million seconds for " + totalCount + " submultiples");
}
private static void get64PrimeNumber(int[] primeNumAry) {
Label1: for(int i = 2, count = 0; count < 64; i++){
for(int j = 2; j < i; j++){
if(i % j == 0){
continue Label1;
}
}
primeNumAry[count++] = i;
}
}
}
--------------
For number 1000000000000000000, Total 0 million seconds for 361 submultiples