英文:
What is the cause of failure in this example given in the Go Memory Model document?
问题
在Go内存模型文档http://golang.org/ref/mem中,给出了以下示例:
var a string
var done bool
func setup() {
a = "hello, world"
done = true
}
func main() {
go setup()
for !done {
}
print(a)
}
然后文档对这个示例进行了如下说明:
"由于两个线程之间没有同步事件,不能保证main函数会观察到对done的写入,因此main函数中的循环不一定会结束。"
所以,如果对done变量的写入可能不会被main观察到,那么似乎可以推断**setup()函数永远不会运行。这样理解对吗?如果是这样,是因为程序被重新排序,将go setup()移到了for !done {}**循环之后吗?还是还有其他原因?
我假设如果go setup()语句实际上能够执行,那么setup()函数将被保证被调用,并且done会被设置。这样理解对吗?
谢谢。
英文:
In the Go Memory Model document http://golang.org/ref/mem it gives the following example:
var a string
var done bool
func setup() {
a = "hello, world"
done = true
}
func main() {
go setup()
for !done {
}
print(a)
}
It then says the following of this example.
>"there is no guarantee that the write to done will ever be observed by main, since there are no synchronization events between the two threads. The loop in main is not guaranteed to finish."
So if the write to the done variable may not be observed by main, that would seem to suggest that the setup() function never runs. Is that correct? If so, would it be because the program was reordered to move the go setup() after the for !done {} loop? Or would there be some other reason?
I assume that if the go setup() statement is actually able to be executed, then the setup() function would be guaranteed to be called and done would be set. Is that right?
Thank you.
答案1
得分: 1
《Go编程语言规范》
Go语言规范中介绍了"Go语句"。
"Go语句"可以将一个函数调用作为一个独立的并发线程或goroutine在同一地址空间中启动执行。
函数值和参数在调用的goroutine中按照通常的方式进行评估,但与常规调用不同,程序执行不会等待被调用的函数完成。相反,该函数在一个新的goroutine中独立开始执行。当函数终止时,它的goroutine也终止。如果函数有任何返回值,在函数完成时它们将被丢弃。
"setup()" goroutine可能不会运行:"与常规调用不同,程序执行不会等待被调用的函数完成。"
"Go语句"可以将一个函数调用作为一个独立的并发线程或goroutine在同一地址空间中启动执行。
函数值和参数在调用的goroutine中按照通常的方式进行评估,但与常规调用不同,程序执行不会等待被调用的函数完成。相反,该函数在一个新的goroutine中独立开始执行。当函数终止时,它的goroutine也终止。如果函数有任何返回值,在函数完成时它们将被丢弃。
"setup()" goroutine可能不会运行:"与常规调用不同,程序执行不会等待被调用的函数完成。"
英文:
> The Go Programming Language Specification
>
> Go statements
>
> A "go" statement starts the execution of a function call as an
> independent concurrent thread of control, or goroutine, within the
> same address space.
>
> The function value and parameters are evaluated
> as usual in the calling goroutine, but unlike with a regular call,
> program execution does not wait for the invoked function to complete.
> Instead, the function begins executing independently in a new
> goroutine. When the function terminates, its goroutine also
> terminates. If the function has any return values, they are discarded
> when the function completes.
The setup()
goroutine may not run: "unlike with a regular call, program execution does not wait for the invoked function to complete."
答案2
得分: 1
有很多问题可能会出现。它可能会:
- 在第一个goroutine完成后安排设置goroutine的调度。
- 将更改保存到本地寄存器而不是全局寄存器。(递增整数会更快)
- 部分更新(对于布尔值可能不太可能,但对于字符串可能会有问题)
- 完全丢弃更改
在当前的实现中,与问题1非常接近。假设GOMAXPROCS=1,for !done { }
将永远不会让出给调度器。这意味着设置永远不会运行。
goroutine 在内存分配、通道通信、系统调用以及随机的函数调用时会让出。这只是一个非全面的列表。但它不会在一个什么都不做的循环中让出。你需要某种形式的同步来确保goroutine最终会让出。
我想指出的是,当前实现是否存在问题并不重要。关键是他们已经声明了不保证,并且在实现优化时,他们将假设代码中 done 被主函数观察到和代码中 done 没有被观察到是相同的。
英文:
There are many things that can go wrong. It could:
- schedule the setup goroutine for after the first goroutine completes.
- make the change to a local register instead of the global. (incrementing integers would be much faster)
- partially update (unlikely with a bool, but a string could be problematic)
- drop the change entirely
In the current implementation, something very close to problem 1 occurs. Assuming GOMAXPROCS=1, for !done { }
will never yield to the scheduler. This means setup would never run.
A goroutine yields on memory allocation, channel communication, syscalls, and randomly on function calls. That is a non-exhaustive list. But it will not yield on a for loop that does nothing. You need some form of synchronization to ensure the goroutine eventually yields.
I would like to point out that it doesn't matter whether there is a problem or not in the current implementation. The point is they have declared it is not guaranteed and when they implement optimizations, they will assume code where done is observed by main and code where it is not observed as the same.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论