MIT 6.824 Lecture 2 RPC and Threads Notes

Posted 周某的技术笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MIT 6.824 Lecture 2 RPC and Threads Notes相关的知识,希望对你有一定的参考价值。

MIT 6.824 Lecture 2 RPC and Threads Notes

1 概要

本课没有涉及分布式系统方面的内容,主要是针对本课程 Lab 使用的编程语言 Go 进行了一个简单的介绍,然后讨论了一下多线程并发相关内容。最后是对一个 Go 写的多线程爬虫代码进行了解读,关注点在并发处理、竞态、锁、多线程协作这块。

本课相关的材料:

课堂 Paper: 本课无论文阅读课堂录像: https://www.bilibili.com/video/BV1R7411t71W?p=2课堂 Note: https://pdos.csail.mit.edu/6.824/notes/l-rpc.txt

2 要点

2.1 Why Go

Thread (goroutine) 支持Lock: 锁机制应对并发执行和竞态类型安全方便的 RPC 库GC 内存安全: 垃圾回收

Go 要比 C++ 更容易使用,语言更简单直接,不会有特别的语法和特性,也不会有那么多奇怪的错误。

2.2 关注并发

I/O concurrency: 客户端可以请求多个服务端并发等待响应,服务端处理多个客户端的连接请求,在一个请求进行 IO 操作时可以切换处理另外一个请求的计算;Parallelism: 多线程利用多核,实际系统中应该尽量利用所有 CPU 的计算力;Convenience: 后台运行,方便执行处理一些分离的任务;

不用多线程,可以用异步编程 event-driven 的方式:

单线程单 loop;保存每个状态: 比如请求客户端的状态;根据事件来执行切换执行任务;单个运行无法充分利用多核 CPU;实现相对复杂,使用起来也难以理解

相对大量线程的情况会更优秀,比如有上百万的连接,对应上百万个线程来说,事件驱动更好,节省资源,同时还可以减少线程切换带来的性能损耗。实现上通常可以多个线程,每个线程都有个独立的事件循环来执行任务,这样可以利用多核资源。比如 nginx,是基于多 Worker 线程的事件驱动模型来实现高性能并发处理大量请求的支持。

2.3 多线程的挑战

共享数据、竞态数据: 多线程访问处理容易出现 bug,并发更新可能会出现问题,机器操作可能不是原子指令

需要使用锁来解决这个问题;或者避免共享可变数据;

coordination 多线程协作执行

channelssync.CondwaitGroup

死锁

锁或者 channel 误用,出现彼此依赖释放或者消费的情况,导致了死锁;

2.4 爬虫示例

示例代码主要是实现模拟爬虫处理页面抓取的功能,需要考虑以下内容:

一个页面可能还包含了其他的页面 URL多个页面可能包含同一个 URL,不应该重复抓取多个页面直接包含 URL 可能会构成一个环页面抓取应当并发进行,可以加速整个任务的执行

课堂上主要是介绍了两个版本的并发抓取爬虫:

1 基于锁的并发爬虫

每个发现的 URL 都创建一个抓取页面的线程多个线程之间共享一个 map 数据来记录已经抓取到的页面,避免重复和循环抓取多个线程对共享的 map 数据操作时需要加锁,避免出现竞态并发更新/读取,在 Go 这会导致 panic 或者内部数据异常可以通过 go 编译器自身的 -race 工具来检查代码中的竞态问题

2 基于 Channel 的并发爬虫

区分为 Master 和 Worker 线程Master 线程创建 Worker 线程去抓取单个页面Master 和 Worker 线程之间共享一个 channel,Worker 把抓取到的页面里面包含的 URL 发送到这个 channel;Master 记录 Worker 执行抓取过的 URL,从 channel 获取到新的页面,先检查是否已经抓取过,如果没有则启动新的 Worker 线程抓取,有则跳过;

基于 channel 不需要加锁,是因为记录抓取过页面的 map 数据实际上没有在多个线程中共享,也不存在多线程并发读取更新的情况。但是实际上,channel 数据结构本身在 Go 的实现应该是存在着锁的,这样多个线程每次只有一个线程可以把 URL 发送到 channel 中。

3 总结

本课内容相对简单,Go 语言对于并发的支持比较好,提供了方便的线程(goroutine) 启动方式,此外还对多线程间的协作提供了包括 channel 、sync 等工具来支持。课程原本是用 C++ 来实现 Lab 相关的编码的,近些年在 Go 语言成熟起来后就切换了。使用 Go 来学习和实现分布式系统,可以让学生更关注分布式系统本身相关的内容,而不是在 C++ 的语言特性和代码 Bug 中花费大量的时间。

Go 语言本身也比较适合网络编程,在业界中有不少的成熟的分布式系统实现,比如 etcd、TiDB、Kubernetes 等。


以上是关于MIT 6.824 Lecture 2 RPC and Threads Notes的主要内容,如果未能解决你的问题,请参考以下文章

MIT 6.824学习笔记 2: RPC and Threads

mit 6.824 lab1分析

MIT-6.824 操作系统 汇总

2020 MIT 6.824 分布式系统课程

MIT 6.824 : Spring 2015 lab2 训练笔记

MIT 6.824 Lab 1 MapReduce