MIT 6.824 Lec2.RPC and Threads

学习本次课程需要对Go语言有一定的了解,推荐Google官方的Go教程 A Tour of Go

线程

多个线程允许一个程序同时进行多项任务,每个线程内部程序串行运行,并且有自己的程序计数器、寄存器和栈空间。

使用线程的优点

多线程的应用在分布式系统中非常常见,因为它能够支持并发操作,非常契合分布式系统的特点。

  • I/O concurrency
    – 使用线程可以同时处理大量的I/O任务。一种常见的场景是,client构建多个线程来向不同的server发起rpc请求,每个请求线程得到响应后再执行对应的处理任务。
  • Multicore performance
    – 使用多线程可以最大限度的利用多核CPU的性能。多个线程可以由不同的CPU核心进行处理,不同CPU核心的线程拥有独立的CPU周期。
  • Convenience
    – 很多时候多线程可以大大简化我们的编程难度。比如在分布式系统中,我们想要每隔一定的时间进行一次事件检查(如 MapReduce中Master节点检查Worker是否异常),我们就可以创建一个线程,让其专门负责定期检查Worker是否存活。

事件驱动编程

如果要实现并发I/O,除了采取多线程的方式,还可以采用事件驱动编程的思想来实现,如epoll模型等。在事件驱动编程中,有一个线程会负责循环检测所有的事件状态,如客户端发起的rpc请求等,当该线程检测到事件到来时,如服务器响应rpc请求,该线程就会调用相应的处理函数,并继续进行循环监听。事件驱动编程相比多线程的实现方式有以下不同:

  • 优点
    – 开销更小(多线程的创建和删除以及空间占用远大于事件驱动)
  • 缺点
    – 无法充分利用多核CPU的性能
    – 实现较为复杂

线程中的挑战

在进行多线程编程时,通常需要仔细考虑以下几个重要问题。

  • shared data
    – 线程间是可以共享进程数据的,但是在使用共享数据的过程中,很可能会出现冲突问题。如两个线程同时执行n=n+1,由于读写的先后顺序不一致,程序产生的结果也会不一样。
  • coordination
    – 我们经常需要线程间能够相互协作,比如经典的消费者-生产者模型。在Go语言中,线程间的相互协作通常有以下几种实现方式,channelsync.Condsync.WaitGroup
  • deadlock

Example: web crawler

下面用一个简单的网页爬虫来展示Go中多线程的应用,对于一个网页爬虫,我们需要其从给定的url出发不断递归查询,并且每个url只能爬取一次。我们首先先给出基本的数据结构。

//
// main
//

func main() {
   
	fmt.Printf("=== Serial===\n")
	Serial("http://golang.org/", fetcher, make(map[string]bool))

	fmt.Printf("=== ConcurrentMutex ===\n")
	ConcurrentMutex("http://golang.org/", fetcher, makeState())

	fmt.Printf("=== ConcurrentChannel ===\n")
	ConcurrentChannel("http://golang.org/", fetcher)
}

//
// Fetcher
//

type Fetcher interface {
   
	// Fetch returns a slice of URLs found on the page.
	Fetch(url string) (urls []string, err error)
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
   
	body string
	urls []string
}

func (f fakeFetcher) Fetch(url string) ([]string, error) {
   
	if res, ok := f[url]; ok {
   
		fmt.Printf("found:   %s\n", url)
		return res.urls, nil
	}
	fmt.Printf("missing: %s\n", url)
	return nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
   
	"http://golang.org/": &fakeResult{
   
		"The Go Programming Language",
		[]string{
   
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
   
		"Packages",
		[]string{
   
			"http://golang.org/"
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值