---
description: AI 设计核心 —— 操作系统设计理念下的中枢
---

# OS Kernel

在接触了操作系统的设计理念后，我一直想用操作系统的思想来设计我的 AI 的核心。因为操作系统的设计方法会带来许多的优势。

简单地说，操作系统是对底层硬件进行直接控制，并为上层应用提供接口。它负责调度、处理一切运行在硬件上的程序，以及管理外设。

### 优势

因为有了中间这一层抽象，所以很显然，我们可以：

1. ⏲️ 监控 <mark style="color:green;">CPU</mark> 消耗，而不必依赖 profiler。事实上，根据我的使用体验，profiler不能一直开着，开着比不开所产生的 <mark style="color:green;">CPU</mark> 消耗会多很多。
2. 📦 引入进程的概念，将运行的逻辑包装成一个进程，交给操作系统调度。因为有了进程，那么就有了特权级，以及时间片。我们就可以在 <mark style="color:green;">CPU</mark> 有限的情况下，自由的调度哪些进程可以被执行。（例如：现在正在发动战争，那么 <mark style="color:green;">CPU</mark> 资源会被优先供应给<mark style="color:red;">战争</mark>模块，而暂时停掉<mark style="color:yellow;">外矿</mark>之类）通过这一个中间层的引入，那么在进程的角度上，就不用考虑现在是不是有没有<mark style="color:red;">战争</mark>之类，只需要做自己的事情就可以了，达到了调度与执行**解耦**的目的。
3. 🧬 在原本的进程设计中，状态是分为就绪、运行、阻塞、结束、挂起就绪和挂起阻塞的。但是显然我们不需要挂起状态。所以只剩就绪、运行、阻塞、结束状态。有了这些概念，我们就可以非常容易地控制模块的运行、中止和停止。同时，再结合信号量，我们就可以完成进程间的**依赖**关系。例如，我们要对 _Creep_ 去 Boost，那么再预约了资源和 <mark style="color:purple;">Lab</mark> 空位之后，我们需要 "将化合物搬到 <mark style="color:purple;">Lab</mark>", "_Creep_ 移动到 <mark style="color:purple;">Lab</mark>" -> "Boost _Creep_"，这三个事件可以同时发出，但是只有当前两个进程都完成后，最后一个进程才会被唤醒。相比而言，在传统的设计当中，如果要实现这种时序依赖关系，可能需要通过 callback 来实现，但是这样的话，会比较类似于一棵树。而通过进程的引入，我们可以做到一张图的效果。会更自由一些。
4. 🔋 在操作系统中，需要对共享资源进行统一管理，其中比较常用的方法就是信号量和管程。那么，对于**资源的管理**，我们就可以借助信号量集来进行任意数量的控制，并且可以设置底线。在我过去写 AI 的经历当中，有一类 BUG 非常的常见，就是比如 <mark style="color:orange;">Spawn</mark> 需要能量的同时，<mark style="color:blue;">Tower</mark> 也需要能量。那么两个填充能量的任务发布在同一 tick 检查能量充足，同时发出任务。在接下来的 tick 中，两个任务都各自独立运行，设置会生出更多的 _Creep_ 来支撑更多的运输量。但是实际上，能量只够一个任务，那么有一个任务成功取得能量继续执行之后，另一个任务会因为能量不够，返回失败，等待下一轮任务发布。这不仅仅浪费资源，而且可能会导致某项任务永远也完不成。
5. ⌛ 在 [Scorpior 的文集](https://zhuanlan.zhihu.com/p/104412058)当中，提到了一种很有用的设计，就是计时器，它可以定时的发布任务。例如，对于一个外矿房间，我们为了让 <mark style="color:green;">Controller</mark> 的 Reservation 能够连上，可能在它结束前 500 tick就提前发布重新 reserve <mark style="color:green;">Controller</mark> 的任务。它比较类似于 cron，我们可以在 Kernel 中挂一个 Timer 来支持该项功能。
