batch replace escape

This commit is contained in:
Xargin
2016-10-18 13:29:52 +08:00
parent 3da62d2c3f
commit d3ce2c9ba6
8 changed files with 15 additions and 15 deletions

View File

@@ -2,7 +2,7 @@
即使我们小心到不能再小心但在并发程序中犯错还是太容易了。幸运的是Go的runtime和工具链为我们装备了一个复杂但好用的动态分析工具竞争检查器(the race detector)。
只要在go buildgo run或者go test命令后面加上-race的flag就会使编译器创建一个你的应用的“修改”版或者一个附带了能够记录所有运行期对共享变量访问工具的test并且会记录下每一个读或者写共享变量的goroutine的身份信息。另外修改版的程序会记录下所有的同步事件比如go语句channel操作以及对(\*sync.Mutex).Lock(\*sync.WaitGroup).Wait等等的调用。(完整的同步事件集合是在The Go Memory Model文档中有说明该文档是和语言文档放在一起的。译注https://golang.org/ref/mem)
只要在go buildgo run或者go test命令后面加上-race的flag就会使编译器创建一个你的应用的“修改”版或者一个附带了能够记录所有运行期对共享变量访问工具的test并且会记录下每一个读或者写共享变量的goroutine的身份信息。另外修改版的程序会记录下所有的同步事件比如go语句channel操作以及对`(*sync.Mutex).Lock``(*sync.WaitGroup).Wait`等等的调用。(完整的同步事件集合是在The Go Memory Model文档中有说明该文档是和语言文档放在一起的。译注https://golang.org/ref/mem)
竞争检查器会检查这些事件会寻找在哪一个goroutine中出现了这样的case例如其读或者写了一个共享变量这个共享变量是被另一个goroutine在没有进行干预同步操作便直接写入的。这种情况也就表明了是对一个共享变量的并发访问即数据竞争。这个工具会打印一份报告内容包含变量身份读取和写入的goroutine中活跃的函数的调用栈。这些信息在定位问题时通常很有用。9.7节中会有一个竞争检查器的实战样例。

View File

@@ -71,7 +71,7 @@ for url := range incomingURLs() {
}
```
我们可以使用测试包(第11章的主题)来系统地鉴定缓存的效果。从下面的测试输出我们可以看到URL流包含了一些重复的情况尽管我们第一次对每一个URL的(\*Memo).Get的调用都会花上几百毫秒但第二次就只需要花1毫秒就可以返回完整的数据了。
我们可以使用测试包(第11章的主题)来系统地鉴定缓存的效果。从下面的测试输出我们可以看到URL流包含了一些重复的情况尽管我们第一次对每一个URL的`(*Memo).Get`的调用都会花上几百毫秒但第二次就只需要花1毫秒就可以返回完整的数据了。
```
$ go test -v gopl.io/ch9/memo1
@@ -300,7 +300,7 @@ func (memo *Memo) Close() { close(memo.requests) }
上面的Get方法会创建一个response channel把它放进request结构中然后发送给monitor goroutine然后马上又会接收它。
cache变量被限制在了monitor goroutine (\*Memo).server中下面会看到。monitor会在循环中一直读取请求直到request channel被Close方法关闭。每一个请求都会去查询cache如果没有找到条目的话那么就会创建/插入一个新的条目。
cache变量被限制在了monitor goroutine ``(*Memo).server`下面会看到。monitor会在循环中一直读取请求直到request channel被Close方法关闭。每一个请求都会去查询cache如果没有找到条目的话那么就会创建/插入一个新的条目。
```go
func (memo *Memo) server(f Func) {
@@ -332,13 +332,13 @@ func (e *entry) deliver(response chan<- result) {
}
```
和基于互斥量的版本类似第一个对某个key的请求需要负责去调用函数f并传入这个key将结果存在条目里并关闭ready channel来广播条目的ready消息。使用(\*entry).call来完成上述工作。
和基于互斥量的版本类似第一个对某个key的请求需要负责去调用函数f并传入这个key将结果存在条目里并关闭ready channel来广播条目的ready消息。使用`(*entry).call`来完成上述工作。
紧接着对同一个key的请求会发现map中已经有了存在的条目然后会等待结果变为ready并将结果从response发送给客户端的goroutien。上述工作是用(\*entry).deliver来完成的。对call和deliver方法的调用必须让它们在自己的goroutine中进行以确保monitor goroutines不会因此而被阻塞住而没法处理新的请求。
紧接着对同一个key的请求会发现map中已经有了存在的条目然后会等待结果变为ready并将结果从response发送给客户端的goroutien。上述工作是用`(*entry).deliver`来完成的。对call和deliver方法的调用必须让它们在自己的goroutine中进行以确保monitor goroutines不会因此而被阻塞住而没法处理新的请求。
这个例子说明我们无论用上锁,还是通信来建立并发程序都是可行的。
上面的两种方案并不好说特定情境下哪种更好,不过了解他们还是有价值的。有时候从一种方式切换到另一种可以使你的代码更为简洁。(译注不是说好的golang推崇通信并发么)
**练习 9.3** 扩展Func类型和(\*Memo).Get方法支持调用方提供一个可选的done channel使其具备通过该channel来取消整个操作的能力(§8.9)。一个被取消了的Func的调用结果不应该被缓存。
**练习 9.3** 扩展Func类型和`(*Memo).Get`方法支持调用方提供一个可选的done channel使其具备通过该channel来取消整个操作的能力(§8.9)。一个被取消了的Func的调用结果不应该被缓存。