从Java到Go的线程

huangapple go评论78阅读模式
英文:

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 &lt; 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 (
  &quot;fmt&quot;
)

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 &lt; 10000; i++ {
	counter.increment()
  }
}

func main() {
  go CountingThread()
  go CountingThread()
  var input string
  fmt.Scanln(&amp;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 (
	&quot;fmt&quot;
	&quot;sync&quot;
)

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 &lt; 10000; i++ {
		counter.increment()
	}
	wg.Done() // mark the goroutine as finished
}

func main() {
	var wg sync.WaitGroup

	wg.Add(2) // we know we&#39;ll wait for 2 goroutines

	go CountingThread(&amp;wg)
	go CountingThread(&amp;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(&amp;c.count, 1)
}

func (c *Counting) getCount() int32 {
        return atomic.LoadInt32(&amp;c.count)
}

See demo at http://play.golang.org/p/68FkSWt6rw.

huangapple
  • 本文由 发表于 2015年9月3日 15:47:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/32369824.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定