我犯过的 Go 语言错误

sync.Mutex.lock 和 sync.Mutex.unlock

mutex.lock() 尝试获取互斥锁,如果锁已被使用,goroutine 会阻塞直到获得互斥锁。 mutex.unlock() 则将已被使用的锁释放, 如果有的goroutine 没有释放获得的互斥锁,则会造成其他goroutine 无法获得互斥锁,从而造成死锁。

if isfetch := safemap.v[url]; isfetch {
		fmt.Println(url," is fetched")
		return
} else {
		safemap.v[url] = true
}
safemap.Unlock()
if isfetch := safemap.v[url]; isfetch {
		fmt.Println(url," is fetched")
		// 此处容易忘记解锁
		safemap.Unlock()
		return
} else {
		safemap.v[url] = true
		safemap.Unlock()
}

sync.WaitGroup

WaitGroup 用于等待一组 goroutine 结束,主 goroutine 调用 Add() 设置要等待的 goroutine 的数目。 每个 goroutine 结束时调用 Done()。同时主 goroutine 调用 Wait() ,阻塞主 goroutine 知道 所有的 goroutine 结束。 第一次使用 WatiGroup 实例后, 该 WaitGroup 一定不能被拷贝。更多的信息可以从不能被拷贝的结构 中获得。

WaitGroup 是结构体,不是引用类型,所以传递给 goroutine 时不能直接传值,而要传递 WaitGroup 实例的指针.

package main

import "sync"

func Crawl(url string, depth int, fetcher Fetcher, waitgroup sync.WaitGroup) {
	...
}

func main() {
	wg := sync.WaitGroup{}
	wg.Add(1)
	go Crawl("http://golang.org/", 4, fetcher, wg)
	wg.Wait()
}

使用 go vet 可以检测到这个错误

MacBookPro:crawler zhuqiuzhi$ go vet crewler.go
crewler.go:24: Crawl passes lock by value: sync.WaitGroup contains sync.noCopy
crewler.go:49: call of Crawl copies lock value: sync.WaitGroup contains sync.noCopy
crewler.go:58: call of Crawl copies lock value: sync.WaitGroup contains sync.noCopy
exit status 1
package main

import "sync"

func Crawl(url string, depth int, fetcher Fetcher, waitgroup *sync.WaitGroup) {
	...
}

func main() {
	wg := sync.WaitGroup{}
	wg.Add(1)
	go Crawl("http://golang.org/", 4, fetcher, &wg)
	wg.Wait()
}