山景城一周记(04/08)

纽约 (04/02)

纽瓦克

周一的美东时间 6 点,我和朋友搭上最早的一班机返回旧金山。在上飞机之前,我还在对作业进行最后的修订。没办法,对于一个典型的 CMU 工程系学生来说,这大概是自由和学业的共同代价吧。

在美东的时候我给自己的日程安排是 hard mode(对于我这种 socialphobic 来说)。到达纽瓦克的当天夜里还在面试,而接下来每一个午餐和晚饭都排满了。唯一空缺的是某天晚上的校友聚会。本科留美的人不多,新老校友到场的不过三十多号人,留美最顶尖的一批校友谈论我们未来的发展,而赴美的新生们各有各的迷茫。时代的沉重,在留美这条路给人带来的分化可见一斑。

我在纽约见面的人大抵可以分为两类:工业界的工程师,以及工业界的 scientist. 我一直以来的观点就是:想要成为一个顶尖的工程师,其天赋、努力与付出不输同样塑造的学术界选手。但我不得不说的是,我在和经受过完整学术界工作训练的人聊天时,能感受到一种很难从工业界塑造中得到的沉稳以及对自己领域内方向的笃定。

Anyway, 我还在计划第二次美东之行。波士顿和匹兹堡各 1 - 2 天,也许会有多伦多。

Moffett Field

学校这边,workload 一点也没有放松。接踵而来的 quiz,lab project,几千行的 Go 接着几千行的 C 接着几千行的 JavaScript。作业有意义吗?我们的课程看起来都很硬核,受技术圈子的广泛认可。然而事实是“隔行如隔山”,教授、科研导师和工业界(包括开源界)赋予每一个人的认可都是基于完全不同的标准,这种标准会附带一种期许,直接影响你对每一个 role 底层意义的判断。我目前消解迷茫的方法无非是抛开各种疑虑,广泛和不同的人交流,然后保持一种学习者的心态。

这周最大的挑战来源于和 peer 写一个分布式文件系统。两个人总共花费了 25 个小时左右。架构不复杂,我们在 nameserver - storageserver 用双重锁的机制规避掉了大部分文件系统操作的一致性的问题,然后抽象一个小层专门应对 replication 的一致性问题。由于 autograder 框架的问题,我们在调试 goroutine panic 的时候绕了一点弯路,最后单独为每一个操作写了 recover log 的时候,基本也把那些空指针、死锁的问题修得七七八八了。

其中一个难点是 Lock 操作 —— 我们需要为每一个文件系统节点加入 Fair Read-Write Lock:对于一个加了 Read Lock 的文件,如果有一个 Write Lock 请求已经在等待释放,那么接下来的 Read Lock 请求必须等待这个 Write Lock 解锁才能 unblock。这一定程度上避免了 starvation,但是 Go 同步原语如 Condition 的内置队列并不符合我们的需求。我们最后选择自行维护一个队列。

type Request struct {
	isRead bool
	wait chan struct{}
}

// FRWLock is a fair read-write lock
type FRWLock struct {
	mu      sync.Mutex
	readers int
	writers int
    
	queue []Request
    
	log   *log.Logger
}

这里的 notify 机制用关闭一个 0-length channel 来实现。考虑到 Request 本身很轻量而且 channel 本身是“引用类型”,我们在 enqueue 的时候没有使用指针,而是直接传 value.

func (rw *FRWLock) RLock() {
    rw.mu.Lock()
    defer rw.mu.Unlock()
    if rw.writers > 0 || len(rw.queue) > 0 {
        // enqueue request
        rw.queue = append(rw.queue, req)
		
        // wait for enqueued locks
        rw.mu.Unlock()
        <-req.wait
        rw.mu.Lock()
        
        // starting here, the current RLock (shared lock) is acquired.
        // any shared lock that follows can succeed as well
        rw.nextRead()
    }

    rw.readers++
	
}

func (rw *FRWLock) RUnlock() {
    rw.mu.Lock()
    defer rw.mu.Unlock()

    rw.readers--
    if rw.readers == 0 {
       rw.nextReadOrWrite()
    }
}

func (rw *FRWLock) nextRead() {
    if len(rw.queue) > 0 && rw.queue[0].isRead {
        close(rw.queue[0].wait)
        rw.queue = rw.queue[1:]
    }
}

func (rw *FRWLock) nextReadOrWrite() {
    ...
}

其实在 Malloc Lab, Shell Lab, Raft Lab 等等项目还有很多有意思的 trick,限于篇幅,就不展开叙述了。

Misc

  • 我还是会怀念之前 startup 的氛围,大家会讨论工业界的真实需求、评价 startup 以及学术界的 ideas,对如何启动并 scale up 一个项目也颇有想法。不过初到美国,我觉得获得初步的认可最重要,只有这样我才能来到一个可以高速成长的土壤。
  • 从学术界的朋友的公开记录中我也羡慕他们颇有广泛学习的能力,然而经历了几年工业界的洗礼再回归校园,我发现自己的阅读量已经大不如前 —— 或者说,繁忙的生活并没有留那么多空间给 diverse exploration. 我曾经很有意愿去搭建自己的“学习-应用-分享”闭环,然而博客的草稿箱积压了好多文章,最终还是没有发出来,或者是我总是羞于把一篇 60-70 分的文章发出来,总是希望能把这篇文章打磨到 80 分,能 match 上我的 peers。也许 Weekly 是一个改变的机会?
  • 可能平时太社恐 + stealth 了,聚会上很多同学听说我今年才来都很惊讶,只好一遍遍的哭惨,“唉,那个时候英国准备赶我出境,然后世界上那两个最邪恶的国家又不要我,一个卡我核酸,另一个卡我学生签,就逃到小坡岛上去了...”
Show Comments