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