能在编码时做的事,就不要推迟到运行时

发布时间:2019-06-17 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了能在编码时做的事,就不要推迟到运行时脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

TL.DR

@H_406_3@软件是一个巨大的有限状态机。工程师日常做的bug修复、性能调优,本质上就是尽可能保证代码处于有序状态下。
不论OC还是Swift,都拥有强大的编译器作为辅助。尽可能多地将状态固定在编码时,就就减少了运行期的状态,使得软件的状态总数减少了。

状态总数少了,错误就少了,性能也就提升了。

Case 1:OC Runtime的Non fragile ivars

这个例子的关键点性能

OC为了做到ABI兼容,改变了C、C++以来对象的内存结构,每个成员变量都需要两次寻址才能访问到。比如要获取obj的第n个变量的偏移地址,就要

*((&obj->isa.cls->data()->ro->ivars->first)[N]->offset);

看起来就慢爆了。

在实现上,LLVM为每个类的每个成员变量都分配了一个全局变量,用于存储该成员变量的偏移值。这样,访问每个变量需要两次寻址,先获取全局变量,再取全局变量的值作为地址找到真正的变量。

编译后的

obj->;myInt = 42;

对应于如下的简单c语言代码

int32_t g_ivar_MyClass_myInt = 40;  // 全局变量
*(int32_t *)((uint8_t *)obj + g_ivar_MyClass_myInt) = 42;

这就是为什么ivar_t.offset用int指针来存储偏移值,而不是直接放一个int的原因

struct ivar_t {
    int32_t *offset;  //注意,这里是指针
    const char *name;
    const char *tyPE;
    
    //...
}

真正存放偏移值的地址是固定不变的,在编译时就确定了下来。因此才能用区区2条指令搞定动态布局的成员变量。

Case 2:矩阵相乘

这个例子的关键点是减少错误

能在编码时做的事,就不要推迟到运行时

如图所示,要保证第一个矩阵中的列数必须与第二个矩阵中的行数相同。简单的做法是做运行时检查

struct Matrix {
  let rows: Int
  let columns: Int
}

func multiply(m1: Matrix, _ m2: Matrix) -> Matrix? {
  // do the matrices have the correct sizes?
  precondition(m1.columns == m2.rows)
  
  // bunch of math...
}

更好的做法是在编码时,就不允许出现行列不等的情况

protocol Dimension {
  static var size: Int { get set }
}

func multiply<U: Dimension, V: Dimension, W: Dimension>
             (m1: Matrix<U,V>, _ m2: Matrix<V,W>) -> Matrix<U,W> {
  // bunch of math...
  return Matrix<U,W>()
}

运行结果

struct NumExamples: Dimension { static var size = 20 }
struct NumFeatures: Dimension { static var size = 10 }
struct OneDimensional: Dimension { static var size = 1 }

let A = Matrix<NumExamples, NumFeatures>()
let B = Matrix<NumFeatures, OneDimensional>()

let C = multiply(A, B)   // yay!

let D = multiply(B, A)   // compiler error
完整的优化过程不在本文的讨论范围内,感兴趣的可以看这里

参考链接

objc explain: Non-fragile ivars
Dynamic ivars: solving a fragile base class problem
编程世界的熵增原理

脚本宝典总结

以上是脚本宝典为你收集整理的能在编码时做的事,就不要推迟到运行时全部内容,希望文章能够帮你解决能在编码时做的事,就不要推迟到运行时所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。