是否需要同步?

Is synchronization required?

我在对象中定义了一个变量 (r.something)

func (r *Runner) init() {
  r.something = make(map[string]int)
  r.something["a"]=1

  go r.goroutine()
}

而 r.goroutine 使用存储在 r.something 中的值而不同步。 除了 r.goroutine()

之外,没有其他人会 read/write 这个值

不同步是否安全?

换句话说:我想重用在 goroutine 启动之前在其他地方初始化的goroutine 中的一些变量。安全吗?

附加问题: r.goroutine() 完成后,我希望能够从其他地方使用 r.something(没有 read/write 与其他 goroutines 重叠)。也安全吗?

如果不存在不同go-routines对读写操作的重叠的情况,那么你是对的:不需要任何同步。

正如您所提到的,在您的 go-routine 开始之前初始化了变量,您实际上是安全的。

是的,很安全。根据Go Memory Model:

  • 启动新 goroutine 的 go 语句发生在 goroutine 开始执行之前
  • 在单个goroutine中,happens-before顺序就是程序表达的顺序

这意味着您在启动 goroutine 之前对变量所做的所有更改都在此 goroutine 中可见。

回答您的附加问题:视情况而定。通常如果 r.goroutine() 修改了 r.something 并且你想从另一个 goroutine 读取它你需要使用同步。

当然这是安全的,否则用 Go 编程可能是一场噩梦(或者至少不那么愉快)。 The Go Memory Model 是一篇有趣的文章。

例程创建是一个同步点。有一个例子与你的非常相似:

var a string

func f() {
    print(a)
}

func hello() {
    a = "hello, world"
    go f()
}

评论如下:

calling hello will print "hello, world" at some point in the future (perhaps after hello has returned).

这是因为:

The go statement that starts a new goroutine happens before the goroutine's execution begins.

单词 before 在这里很重要,因为它意味着例程创建(在一个线程中)必须与其开始同步(可能在其他线程中),因此写入 a 必须对新例程可见。