fix typo and optimize.

Change-Id: I7b6938936231fd722814984678ffa30402539fd9
This commit is contained in:
fuyc
2016-08-11 17:08:38 +08:00
parent ed57986ea7
commit 8fda418f3a
33 changed files with 128 additions and 126 deletions

View File

@@ -100,7 +100,7 @@ func makeThumbnails4(filenames []string) error {
这个程序有一个微秒的bug。当它遇到第一个非nil的error时会直接将error返回到调用方使得没有一个goroutine去排空errors channel。这样剩下的worker goroutine在向这个channel中发送值时都会永远地阻塞下去并且永远都不会退出。这种情况叫做goroutine泄露(§8.4.4)可能会导致整个程序卡住或者跑出out of memory的错误。
最简单的解决办法就是用一个具有合适大小的buffered channel这样这些worker goroutine向channel中发送测向时就不会被阻塞。(一个可选的解决办法是创建一个另外的goroutine当main goroutine返回第一个错误的同时去排空channel)
最简单的解决办法就是用一个具有合适大小的buffered channel这样这些worker goroutine向channel中发送错误时就不会被阻塞。(一个可选的解决办法是创建一个另外的goroutine当main goroutine返回第一个错误的同时去排空channel)
下一个版本的makeThumbnails使用了一个buffered channel来返回生成的图片文件的名字附带生成时的错误。
@@ -174,7 +174,7 @@ func makeThumbnails6(filenames <-chan string) int64 {
}
```
注意Add和Done方法的不对。Add是为计数器加一必须在worker goroutine开始之前调用而不是在goroutine中否则的话我们没办法确定Add是在"closer" goroutine调用Wait之前被调用。并且Add还有一个参数但Done却没有任何参数其实它和Add(-1)是等价的。我们使用defer来确保计数器即使是在出错的情况下依然能够正确地被减掉。上面的程序代码结构是当我们使用并发循环但又不知道迭代次数时很通常而且很地道的写法。
注意Add和Done方法的不对。Add是为计数器加一必须在worker goroutine开始之前调用而不是在goroutine中否则的话我们没办法确定Add是在"closer" goroutine调用Wait之前被调用。并且Add还有一个参数但Done却没有任何参数其实它和Add(-1)是等价的。我们使用defer来确保计数器即使是在出错的情况下依然能够正确地被减掉。上面的程序代码结构是当我们使用并发循环但又不知道迭代次数时很通常而且很地道的写法。
sizes channel携带了每一个文件的大小到main goroutine在main goroutine中使用了range loop来计算总和。观察一下我们是怎样创建一个closer goroutine并让其等待worker们在关闭掉sizes channel之前退出的。两步操作wait和close必须是基于sizes的循环的并发。考虑一下另一种方案如果等待操作被放在了main goroutine中在循环之前这样的话就永远都不会结束了如果在循环之后那么又变成了不可达的部分因为没有任何东西去关闭这个channel这个循环就永远都不会终止。