从流浪地球550自编程谈操作系统
柏舟 新冠4年 02-01
《流浪地球2》550系列通过自编程动态生成操作系统,大幅提高发动机建造效率,这个想法真的很有趣。操作系统一般用于管理系统资源和外设,而550显然不止于此,发动机系统的机械部件肯定包含其它计算机,550必须拥有集群管理能力,同时有很强的运筹能力。
自编程
自编程真的不是什么新概念,计算机发明初期,还只有汇编的时候,就有运行时生成代码的做法。后来,window的渲染管线中也有动态生成汇编执行的做法。lisp使用宏不仅能够在编译时生成代码,同时能够在运行时不断生成宏或函数,赋予了程序员极大的自由度,能够自由的控制程序执行顺序。
在550中,我认为自编程主要用于外设的驱动生成,远程调用的驱动生成,550量子计算机自身计算特点的代码生成。为什么自编程动态生成操作系统就一定优于传统做法呢?早期的计算机和嵌入式计算机因为计算能力、存储空间有限,只会携带需要的驱动程序,如果需要添加新的设备,就需要重新编译内核。后来,操作系统能够动态安装驱动程序,不需要重新启动。但是,这肯定会增加操作系统的复杂度,将编译期的工作转移到运行期,操作系统的适应能力更强了,但是也变复杂了,更慢了。
那么有没有办法像jit一样,操作系统动态生成最优的代码呢?
理想的操作系统
操作系统究竟是什么东西?有人说,操作系统是C语言的运行时。C语言太简单了,只具有运算的抽象,如果需要调用外设,打印输出,使用多个CPU,使用进程、线程的抽象就必须引入操作系统的接口。
操作系统中很多损耗,比如内核态和用户态的切换,虚拟内存等等都是因为C语言本身不安全造成的。假如,我们确保语言本身安全,是不是就可以取消虚拟内存了呢?比如,将JVM做成操作系统,是不是程序就可以直接在物理内存上跑了呢?
在很多年前,plan9就通过9p协议做了远程服务调用,Erlang在语言层面上做了消息驱动模式的封装,它们屏蔽了调用本地的服务和远程服务的区别。Go语言自己实现了调度器,相当于在操作系统的进程上跑了一个微型的操作系统。但是,这些方法总感觉差了点什么。
进程、线程的抽象是CPU物理的抽象,在计算程序中真的该如此吗?我认为理想的操作系统就像分形一样,操作系统的每个子节点也是操作系统,文件系统的每个文件也是文件系统。其实kubernetes已经很接近了,将容器视作操作系统,在容器中已经可以通过API spawn一个容器了。但问题是,这是一个扁平的结构,而不是树状的分形的结构,而且最大的问题是,spawn的容器必须是已存在的容器,很难通过自编程动态生成新的容器。
我很期待在未来看到,语言有一个对资源、外设的好的抽象。Java .NET能够直接运行在硬件上。操作系统成为是一种跨语言的分形接口,可以屏蔽本地和远程的区别。