我犯过的 Go 语言错误
06 Oct 2017sync.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()
}