英文:
Threads from java to go
问题
以下是将上述代码翻译为Go的尝试:
package main
import (
"fmt"
)
type Counting struct {
count int
}
var counter = Counting{}
func (c *Counting) increment() {
c.count++
}
func (c *Counting) getCount() int {
return c.count
}
func CountingThread() {
for i := 0; i < 10000; i++ {
counter.increment()
}
}
func main() {
go CountingThread()
go CountingThread()
var input string
fmt.Scanln(&input)
fmt.Println(counter.getCount())
}
请注意,由于Go语言中没有直接等待键盘输入的功能,因此我在代码中添加了fmt.Scanln(&input)
来模拟等待输入。这可能会导致输出结果始终为20000,因为在等待输入之前,两个CountingThread
goroutine已经完成了计数操作。如果你想要更准确的结果,请使用其他方式等待goroutine完成,例如使用sync.WaitGroup
。
英文:
How can I translate the below code to Go
, you can see my attempt below but because I'm waiting for a key input the code will always return 20000
where java will output different results. I know that both have a race condition, but I just want to know the translation.
JAVA
public class Counting {
public static void main(String[] args) throws InterruptedException {
class Counter {
private int count = 0;
public void increment() { ++count; }
public int getCount() { return count; }
}
final Counter counter = new Counter();
class CountingThread extends Thread {
public void run() {
for(int x = 0; x < 10000; ++x)
counter.increment();
}
}
CountingThread t1 = new CountingThread();
CountingThread t2 = new CountingThread();
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(counter.getCount());
}
}
Here is my go attempt:
import (
"fmt"
)
type Counting struct {
count int
}
var counter = Counting{}
func (c *Counting) increment() {
c.count++
}
func (c *Counting) getCount() int {
return c.count
}
func CountingThread() {
for i := 0; i < 10000; i++ {
counter.increment()
}
}
func main() {
go CountingThread()
go CountingThread()
var input string
fmt.Scanln(&input)
fmt.Println(counter.getCount())
}
答案1
得分: 1
Goroutines不是线程,因此必须使用同步原语。
你可以使用sync.WaitGroup
来完成翻译(参见http://golang.org/pkg/sync/#WaitGroup)。
package main
import (
"fmt"
"sync"
)
type Counting struct {
count int
}
var counter = Counting{}
func (c *Counting) increment() {
c.count++
}
func (c *Counting) getCount() int {
return c.count
}
func CountingThread(wg *sync.WaitGroup) {
for i := 0; i < 10000; i++ {
counter.increment()
}
wg.Done() // 标记goroutine已完成
}
func main() {
var wg sync.WaitGroup
wg.Add(2) // 我们知道我们将等待2个goroutine
go CountingThread(&wg)
go CountingThread(&wg)
wg.Wait() // 等待goroutine都完成
fmt.Println(counter.getCount())
}
演示链接:http://play.golang.org/p/0SHCvowDjI
它输出了“预期”值20000。
显然,这段代码展示了数据竞争:
$ go run -race race.go
==================
WARNING: DATA RACE
Read by goroutine 6:
main.CountingThread()
race.go:24 +0x48
Previous write by goroutine 7:
main.CountingThread()
race.go:24 +0x5e
Goroutine 6 (running) created at:
main.main()
race.go:34 +0x8f
Goroutine 7 (running) created at:
main.main()
race.go:35 +0xb1
==================
19042
Found 1 data race(s)
exit status 66
可以通过使用原子计数器来解决这个问题:
type Counting struct {
count int32
}
var counter = Counting{}
func (c *Counting) increment() {
atomic.AddInt32(&c.count, 1)
}
func (c *Counting) getCount() int32 {
return atomic.LoadInt32(&c.count)
}
在http://play.golang.org/p/68FkSWt6rw上查看演示。
英文:
Goroutines are not threads, so a synchronization primitive must be used.
Your translation should be done using a sync.WaitGroup
(see http://golang.org/pkg/sync/#WaitGroup).
package main
import (
"fmt"
"sync"
)
type Counting struct {
count int
}
var counter = Counting{}
func (c *Counting) increment() {
c.count++
}
func (c *Counting) getCount() int {
return c.count
}
func CountingThread(wg *sync.WaitGroup) {
for i := 0; i < 10000; i++ {
counter.increment()
}
wg.Done() // mark the goroutine as finished
}
func main() {
var wg sync.WaitGroup
wg.Add(2) // we know we'll wait for 2 goroutines
go CountingThread(&wg)
go CountingThread(&wg)
wg.Wait() // wait for the goroutines to both finish
fmt.Println(counter.getCount())
}
Demonstration here: http://play.golang.org/p/0SHCvowDjI
It outputs the "expected" value of 20000.
Obviously this code demonstrates a data race:
$ go run -race race.go
==================
WARNING: DATA RACE
Read by goroutine 6:
main.CountingThread()
race.go:24 +0x48
Previous write by goroutine 7:
main.CountingThread()
race.go:24 +0x5e
Goroutine 6 (running) created at:
main.main()
race.go:34 +0x8f
Goroutine 7 (running) created at:
main.main()
race.go:35 +0xb1
==================
19042
Found 1 data race(s)
exit status 66
This can be solved by the use of an atomic counter:
type Counting struct {
count int32
}
var counter = Counting{}
func (c *Counting) increment() {
atomic.AddInt32(&c.count, 1)
}
func (c *Counting) getCount() int32 {
return atomic.LoadInt32(&c.count)
}
See demo at http://play.golang.org/p/68FkSWt6rw.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论