Anf*_*nee 5 concurrency struct go race-condition goroutine
从戴夫·切尼博客,下面的代码显然会导致比赛的情况下仅通过改变来解决func (RPC) version() int到func (*RPC) version() int:
package main
import (
"fmt"
"time"
)
type RPC struct {
result int
done chan struct{}
}
func (rpc *RPC) compute() {
time.Sleep(time.Second) // strenuous computation intensifies
rpc.result = 42
close(rpc.done)
}
func (RPC) version() int {
return 1 // never going to need to change this
}
func main() {
rpc := &RPC{done: make(chan struct{})}
go rpc.compute() // kick off computation in the background
version := rpc.version() // grab some other information while we're waiting
<-rpc.done // wait for computation to finish
result := rpc.result
fmt.Printf("RPC computation complete, result: %d, version: %d\n", result, version)
}
Run Code Online (Sandbox Code Playgroud)
在查看代码几次之后,我很难相信代码有一个种族案例.但是,当使用--race运行时,它声称有一个写入rpc.result=42和之前的读取version := rpc.version().我理解写作,因为goroutine改变了它的值rpc.result,但读取了什么呢?该version()方法在何处进行读取?它不会触及任何rpc的值,只返回1.
我想了解以下内容:
1)为什么特定行被认为是对rpc结构的读取?
2)为什么要改变RPC以*RPC解决比赛案例?
当你有一个像这样的值接收器的方法:
func (RPC) version() int {
return 1 // never going to need to change this
}
Run Code Online (Sandbox Code Playgroud)
你称之为这种方法:
version := rpc.version() // grab some other information while we're waiting
Run Code Online (Sandbox Code Playgroud)
必须从值中创建一个副本,该值rpc将传递给方法(用作接收器值).
因此,当一个goroutine go rpc.compute()正在运行并且正在修改rpcstruct value(rpc.result = 42)时,主goroutine正在复制整个rpcstruct值.那里!这是一场比赛.
将接收器类型修改为指针时:
func (*RPC) version() int {
return 1 // never going to need to change this
}
Run Code Online (Sandbox Code Playgroud)
你称之为这种方法:
version := rpc.version() // grab some other information while we're waiting
Run Code Online (Sandbox Code Playgroud)
这是一个简写
version := (&rpc).version()
Run Code Online (Sandbox Code Playgroud)
这会将rpc值的地址传递给RPC.version()它,它只使用指针作为接收器,因此不会复制rpcstruct值.因为结构中没有任何东西被使用/读入RPC.version(),所以没有种族.
注意:
请注意,如果RPC.version()将读取该RPC.result字段,它也将是一个竞赛,因为一个goroutine修改它,而主goroutine将读取它:
func (rpc *RPC) version() int {
return rpc.result // RACE!
}
Run Code Online (Sandbox Code Playgroud)
笔记2:
另请注意,如果RPC.version()读取的其他字段RPC未被修改RPC.compute(),则不会是竞赛,例如:
type RPC struct {
result int
done chan struct{}
dummy int
}
func (rpc *RPC) version() int {
return rpc.dummy // Not a race
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
77 次 |
| 最近记录: |