返回

延迟满足:在编码时做出决策

IOS

无论何种类型的软件都包含大量状态,以各种方式组合。工程师日常做的 bug 修复、性能调优,本质上就是尽可能保证代码处于有序状态下。

编写编码时,我们的目标是尽可能多地将状态固定下来,这样就减少了运行期的状态,使得软件的状态总数减少了。

更少的运行时状态意味着软件更少可能陷入错误状态,因为这些错误状态的总量就是运行时状态的总和。

另外,运行时状态越少,我们修复 bug 的难度也越低,因为代码的运行方式更少。

下面我们以矩阵相乘为例来说明这一原理。

矩阵相乘是一个经典的算法问题。给定两个矩阵 A 和 B,我们要计算它们的乘积 C。

C 的元素可以通过以下公式计算:

C(i, j) = Σ(A(i, k) * B(k, j))

其中,i 和 j 是矩阵 C 的行索引和列索引,k 是矩阵 A 和 B 的列索引和行索引。

我们可以用嵌套循环来实现矩阵相乘算法。外层循环迭代矩阵 C 的行,内层循环迭代矩阵 C 的列。在内层循环中,我们使用第三个循环来计算 C 的每个元素。

for i in range(num_rows_a):
    for j in range(num_cols_b):
        for k in range(num_cols_a):
            c[i][j] += a[i][k] * b[k][j]

这种实现方式存在一个问题:它在运行时会创建大量临时状态。例如,在每次迭代内层循环时,我们都需要创建一个新的变量来存储 C(i, j) 的值。

为了减少运行时的状态,我们可以对算法进行一些修改。首先,我们可以将 C(i, j) 的值存储在一个临时变量中,然后在内层循环的末尾将该值赋给 C(i, j)。

for i in range(num_rows_a):
    for j in range(num_cols_b):
        temp = 0
        for k in range(num_cols_a):
            temp += a[i][k] * b[k][j]
        c[i][j] = temp

这种修改减少了运行时的状态,因为我们不再需要在每次迭代内层循环时创建一个新的变量来存储 C(i, j) 的值。

其次,我们可以将矩阵 A 和 B 的元素存储在连续的内存块中。这样,我们就可以使用指针来访问矩阵的元素,而不需要使用下标。

float* a_ptr = &a[0][0];
float* b_ptr = &b[0][0];
float* c_ptr = &c[0][0];

for (int i = 0; i < num_rows_a; i++) {
    for (int j = 0; j < num_cols_b; j++) {
        float temp = 0;
        for (int k = 0; k < num_cols_a; k++) {
            temp += a_ptr[i * num_cols_a + k] * b_ptr[k * num_cols_b + j];
        }
        c_ptr[i * num_cols_b + j] = temp;
    }
}

这种修改也减少了运行时的状态,因为我们不再需要在每次迭代内层循环时创建一个新的变量来存储 C(i, j) 的值。

通过这些修改,我们减少了矩阵相乘算法运行时的状态。这使得算法运行得更快,也更不容易出错。