英文:
Golang Goroutines - Fix Race Condition using Atomic Functions
问题
我是一个 Golang 的新手,我正在尝试理解 goroutines。下面是我从 https://www.golangprograms.com/goroutines.html 上找到的一段代码。
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
)
var (
counter int32 // counter 是所有 goroutine 增加的变量。
wg sync.WaitGroup // wg 用于等待程序完成。
)
func main() {
wg.Add(3) // 添加计数,每个 goroutine 一个。
go increment("Python")
go increment("Java")
go increment("Golang")
wg.Wait() // 等待 goroutine 完成。
fmt.Println("Counter:", counter)
}
func increment(name string) {
defer wg.Done() // 调度 Done 来告诉主程序我们已经完成。
for range name {
fmt.Println("name:", name)
fmt.Println("Counter in range:", counter)
atomic.AddInt32(&counter, 1)
runtime.Gosched() // 让出线程并重新排队。
}
}
输出:
name: Golang
Counter in range: 0
name: Java
Counter in range: 1
name: Golang
Counter in range: 2
name: Golang
Counter in range: 3
name: Java
Counter in range: 4
name: Golang
Counter in range: 5
name: Python
Counter in range: 6
name: Java
Counter in range: 7
name: Golang
Counter in range: 8
name: Java
Counter in range: 9
name: Golang
Counter in range: 10
name: Python
Counter in range: 11
name: Python
Counter in range: 12
name: Python
Counter in range: 13
name: Python
Counter in range: 14
name: Python
Counter in range: 15
Counter: 16
我无法理解为什么输出是 16。即使我们只添加了 3 个 goroutine,它不应该是 3 吗?
有人可以解释一下吗?
谢谢。
英文:
I am a newbie in Golang and I am trying to understand the goroutines.
Here is the piece of code which I got from https://www.golangprograms.com/goroutines.html.
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
)
var (
counter int32 // counter is a variable incremented by all goroutines.
wg sync.WaitGroup // wg is used to wait for the program to finish.
)
func main() {
wg.Add(3) // Add a count of two, one for each goroutine.
go increment("Python")
go increment("Java")
go increment("Golang")
wg.Wait() // Wait for the goroutines to finish.
fmt.Println("Counter:", counter)
}
func increment(name string) {
defer wg.Done() // Schedule the call to Done to tell main we are done.
for range name {
fmt.Println("name:", name)
fmt.Println("Counter in range:", counter)
atomic.AddInt32(&counter, 1)
runtime.Gosched() // Yield the thread and be placed back in queue.
}
}
Output:
name: Golang
Counter in range: 0
name: Java
Counter in range: 1
name: Golang
Counter in range: 2
name: Golang
Counter in range: 3
name: Java
Counter in range: 4
name: Golang
Counter in range: 5
name: Python
Counter in range: 6
name: Java
Counter in range: 7
name: Golang
Counter in range: 8
name: Java
Counter in range: 9
name: Golang
Counter in range: 10
name: Python
Counter in range: 11
name: Python
Counter in range: 12
name: Python
Counter in range: 13
name: Python
Counter in range: 14
name: Python
Counter in range: 15
Counter: 16
I am unable to understand that why the output is 16. Even we added only 3 goroutines. Shouldn't it be 3?
Can anyone please explain me?
Thanks.
答案1
得分: 3
我无法理解为什么输出是16。即使我们只添加了3个goroutine,它也应该是3吗?
为什么应该是3呢?它应该是atomic.AddInt32(&counter, 1)
被调用的次数。
那是多少次呢?你启动了3个goroutine,每个都有一个循环。递增操作是在循环内部完成的。
循环如下:
for range name {}
for range
循环遍历字符串的字符。在你的例子中,字符串是Golang
、Java
和Python
。所以循环体将根据这些字符串的字符数执行相应的次数:Golang
有6个字符,Java
有4个字符,Python
有6个字符,总共是16次。
英文:
> I am unable to understand that why the output is 16. Even we added only 3 goroutines. Shouldn't it be 3?
Why should it be 3? It should be as many times atomic.AddInt32(&counter, 1)
is called.
How many times is that? You launch 3 goroutines, and each has a loop. Incrementing is done inside the loops.
The loops:
for range name {}
The for range
over a string
iterates over the runes of the string
. The names in your case are Golang
, Java
and Python
. So the loop bodies will be executed as many times as many runes these strings have: 6 for Golang
, 4 for Java
and 6 for Python
, that adds up to 16.
答案2
得分: 0
你正在对给定的输入字符串进行范围遍历,trange将其视为数组并对其进行迭代。看看这个例子:
package main
import (
"fmt"
)
func main() {
increment("test")
increment("test_dev")
increment("test_deploy")
}
func increment(name string) {
for i, value := range name {
fmt.Printf("name: %s index: %d, char: %c\n", name, i, value)
}
}
这段代码会输出字符串中每个字符的索引和值。
英文:
You are range over the given input string, trange treat it as an array and iterates over it.
See this example
package main
import (
"fmt"
)
func main() {
increment("test")
increment("test_dev")
increment("test_deploy")
}
func increment(name string) {
for i, value := range name {
fmt.Printf("name: %s index: %d, char: %c\n", name, i, value)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论