本科做(摸)过(鱼)的一些计院Lab

Posted by Shuenhoy on 06-26,2021

毕业了,回家的火车上无事可做,于是就决定随便记录一下本科做过一些课程的实验/Project,特别是,我在做这些实验/Project时是如何摸鱼的。其中有些课程的内容可能现在已经没有参考价值,我写的东西也有些凌乱,有些摸鱼小技巧可供参考,剩下的就当做是我自己的一份本科回忆罢。

计算机组成

计算机组成不同班的模式似乎不太一样,我们班是单周期部分最后一个实验选做,多周期部分最后两个实验选做。作为一个摸鱼的人,我自然这三个实验都没做。在学期末则有一个大程,要求在单周期或者多周期的系统上做一个应用程序。众所周知,硬件实验最反人类的就是调试,特别是对汇编代码的调试甚至比Verilog还要难受。为了尽可能减少工作量,避免重复上板,从而摸鱼,只好写了一个简单的MIPS模拟器。本来只想通过这样的方式避免不停向板子上写入代码,但是完成之后却发现了另一个惊喜,那就是我可以借助宿主语言的设施实现单元测试了。有了单元测试,瞬间就摆脱了简单粗暴的单步调试,被拆成若干函数的每一部分很快就得到了debug,后来也确实实现了一次上板完工。

数据库系统

数据库系统有两个实验,一是简单的图书管理系统,再就是实现单线程单用户本地数据库,即MiniSQL。说实话,MiniSQL这一实验潜力很大,但是实践上效果却很差,因为这实验缺乏必要的指引和有效的评估。在我看来,最能反映这一实验实践上失败之处的就是Index的部分。据我观察,有相当多的一部分人Index部分写成了纯内存的数据结构,每个节点只存了不超过3个信息,完全失去了使用B+树的意义;一些人实现了其持久化,却也需要在启动时将整个树加载到内存里。而实际上,在写一个数据库这个项目中,真正、最能反映使用B+树意图的应当是使用fseek实现的每个block都是一个节点,只需要将单个节点读取到内存中的磁盘B+树。但不知道为什么,实际上这样写的人似乎很少,实验指导中完全没有体现,验收时助教也没有关注。不过,MiniSQL的实验中确实没有很多可以摸鱼的点,我唯一可能算得上的就是用C#写了MiniSQL,得到了一些便利,但确实算不上摸到了多少鱼。

数字图像处理

数字图像处理只有几个小lab,但是这些lab的体验是很不错的,每个lab粒度相对较小,目标和指引也比较清楚,而且实验也能够看到实际的应用在图像处理上的结果。虽然在图像处理课程的lab上没能摸到多少鱼,但是还是比较推荐的。

操作系统

在大三时恰好遇到了OS课改,可选旧的三个实验(Regular Track)或者一组新的实验(Advanced Track),即从零开始写基于RISC-V的简单OS内核(选这个实验甚至还需要面试)。有五个必做和四个Bonus,每个Bonus可以直接在总评上加2分,看上去十分诱人。这套实验从表面上看比较困难,实际上最考察的还是搜索和阅读理解的能力。作为一个摸鱼惯犯,我自然只做了必做,没有做Bonus。实际上,Bonus的工作量远大于必做,直接在总评上加分看似血赚,其实性价比不高,而必做部分属实不需要太多的工作,每个lab连代码到文档大概只需要三四小时时间。当然,第二年似乎封堵了这个漏洞,将部分Bonus改为了必做。最后,这门课的两个班的助教组非常负责,虽然我没有亲身去体验,但是许多组的同学在遇到问题时都得到了助教的非常详尽耐心的指导,甚至听闻有一位助教学长咕了和女朋友的约会,花了一下午额外的时间答疑和指导,有这样的助教实在是能够令人心安。

程序设计方法学

这门课的Lab是写一个叫做MUA的比较神秘的语言的解释器。在我们这届之前,似乎有着经常改需求的风评,但是到我们时,已经改为了PTA评分,需求固定了下来。不过即便如此,这个Lab还是显得比较神秘。比如老师一直坚持这门课不是编译原理,所以不能出现AST这个概念;再如Lab的三个部分实际上基本是横向扩充,深度没什么变化。如果仿照《EOPL》的框架,将Lab的三个部分重组成了更细的五六个渐进的部分,去掉原本开头(视实现的不同或许不是开头,特别是从坚持不引入AST的概念这一点来看,似乎这个Lab的意图是要把Parser和其他部分耦合在一起的)占很大部分的Parser部分(实际上,这一点也比较奇怪,毕竟明明强调了不是编译原理课程,Lab却有很大工作量是传统上属于的编译原理课程的语法解析),以“编译也是解释”结尾,我觉得可能在工作量相差不大的情况下学到更多东西。当然,这门课程给分还是很厚道的,只有两学分,工作量也不是很大,还是值得一选的。

体系结构

体系的Lab我一开始是十分抗拒,毕竟看起来和计组差异不大,而且pipeline的寄存器有很多无聊的连线工作。为了避免这种无聊让我中途弃坑,我向老师申请了使用chisel代替verilog完成实验。好处是,chisel使用了scala这样一个正儿八经的编程语言,使我可以将许多手工操作改为编程完成;对类型的检查也非常严格,再也不会出现verilog里少打了一个宽度,综合时无事发生(严格来说,它应该给我报了warning,但是ise和vivado的报错也就比latex强,实在是不想去辨别),一下板就跪的情况;当然,chisel的单元测试写起来也舒服多了。但是实际上缺点也不少:scala作为一个jvm系的语言,我其实是拒绝的(虽然这是个非常主观的原因,但是我还是把它放在缺点的首位了——注);sbt实在是太慢了;当时chisel还有很多功能没有stable,不得以还得自己编译unstable的版本;实验从填空题变成了论述题,没有友善的,写好了大致框架给你填的模板了,全部都得自己写了。总之,这段用chisel写体系lab的经历,虽然比较折腾,scala在我当时的垃圾2c4t的电脑上慢的时候也让我怀疑过人生,但是总归让我没有从一开始就丧失兴趣,是件好事。

编译原理

编译原理的Project要求比较简单,就是自己写一个编译器,题材不限。由于当时疫情在家,身心都处于极度摸鱼的状态,怎么划过这个Project就成了一个重要的问题。这时我在整理文件时突然想起,当初大一的小学期的C#课上,我曾经写一个一个Lisp类语言的字节码解释器和从Lisp源码到AST再到这个字节码解释器指令序列的编译器。但是,明眼人都能看出来Lisp的语法过于简单,不够fancy。而且,一点工作都不做,直接复用以前的代码确实也不太好。好在原来的代码抽象做的还可以,我直接把原本的“Lisp源码到AST”这一步(即Parser)去掉,换成了一个类似于ML风格的语言的语法的Parser(当然,后面什么都没改,所以是动态类型的),高性价比地完成了这个Project。

信息检索与Web搜索

这门课本属于误选,错以为它是模块课,结果是个性课。但是大三下本身课程不多,就没有弃修(好吧,其实是过了弃修deadline才发现这个问题——注)。这门课程本身有考试,但是疫情在家改为了考核,相应地project难度也有所提升。这门课程的project是三(也许是四)人组队实现一些经典的检索算法整合成一个系统,比如倒排索引,通配符,拼写矫正等等。总的来说,这个project还是比较有意思的,可以理解一个最低限度的传统的搜索引擎的工作方式。

另外,课上没有什么熟人,我本打算solo,但老师坚持要求组队,于是我便和另外一名也打算solo的同学组成了两人队。从结果来看,这门课程成为了我除去FDS和ADS,整个本科计院的课的Project/Lab中,唯一一次有效的组队,一次我和队友的贡献相仿,工作量相当的组队。

写到这里,我觉得非常有必要作一番检讨。组队时,往往队友的代码实际上已经完全达到了实验的要求,我却可能会因为觉得代码不够优雅就整个重写(比如《数据库系统》课程中的图书管理系统实验就发生了这样的事情)。久而久之,我也有些不太耐烦,不知不觉间就形成了直接自己把代码甚至文档全写了的习惯。不管从任何角度来说,这都确实不是正确的合作方式。机缘巧合之下(老师要求必须组队、队友也本想solo、心理上也不太愿意帮非熟人全写了)促成的这次合作,也让我得以反思之前的做法。以前的行为毋宁说是一种逃避,对组队造成的对工作的掌控度下降的逃避。比起,逃避而自己全包或是干脆不组队直接solo,将工作的一部分放心地交给队友,并积极地促进合作走向大家都满意的境地或许是更好的选择。

所以我在这最后一门课上的摸鱼小技巧就是合理组队(小学生作文式结尾)。