在两个 goroutine 之间同步

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

Sync between 2 goroutines

问题

我的任务是同步两个goroutine,使输出看起来像这样:

foobarfoobarfoobarfoobar

问题在于当我调用它们时,它们的输出完全是随机的。这是我的代码:

package main

import (
	"fmt"
	"sync"
	"time"
)

type ConcurrentPrinter struct {
	sync.WaitGroup
	sync.Mutex
}


func (cp *ConcurrentPrinter) printFoo(times int) {
	cp.WaitGroup.Add(times)
	go func() {
		cp.Lock()
		fmt.Print("foo")
		cp.Unlock()
	}()
}
func (cp *ConcurrentPrinter) printBar(times int) {
	cp.WaitGroup.Add(times)
	go func() {
		cp.Lock()
		fmt.Print("bar")
		cp.Unlock()
	}()
}

func main() {
	times := 10
	cp := &ConcurrentPrinter{}

	for i := 0; i <= times; i++ {
		cp.printFoo(i)
		cp.printBar(i)
	}
	time.Sleep(10 * time.Millisecond)
}
英文:

My task is to sync 2 goroutines so the output should look like that:

> foobarfoobarfoobarfoobar

.The issue is that when I call them they come out completely randomized. This is my code:

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

type ConcurrentPrinter struct {
	sync.WaitGroup
	sync.Mutex
}


func (cp *ConcurrentPrinter) printFoo(times int) {
	cp.WaitGroup.Add(times)
	go func() {
		cp.Lock()
		fmt.Print(&quot;foo&quot;)
		cp.Unlock()
	}()
}
func (cp *ConcurrentPrinter) printBar(times int) {
	cp.WaitGroup.Add(times)
	go func() {
		cp.Lock()
		fmt.Print(&quot;bar&quot;)
		cp.Unlock()
	}()
}

func main() {
	times := 10
	cp := &amp;ConcurrentPrinter{}

	for i := 0; i &lt;= times; i++ {
		cp.printFoo(i)
		cp.printBar(i)
	}
	time.Sleep(10 * time.Millisecond)
}

答案1

得分: 2

如评论中所述,使用goroutine可能不是你试图实现的最佳方案,因此这可能是一个XY问题。

话虽如此,如果你想确保两个独立的goroutine以交替的顺序进行工作,你可以实现一组“乒乓”互斥锁:

var ping, pong sync.Mutex

pong.Lock() // 确保第二个goroutine等待,第一个先执行

go func() {
    for {
        ping.Lock()
        foo()
        pong.Unlock()
    }
}()

go func() {
    for {
        pong.Lock()
        bar()
        ping.Unlock()
    }
}()

https://go.dev/play/p/VO2LoMJ8fek

英文:

As outlined in the comments, using goroutines may not be the best use case for what you are trying to achieve - and thus this may be an XY problem.

Having said that, if you want to ensure two independent goroutines interleave their work in an alternating sequence, you can implement a set of "ping-pong" mutexs:

var ping, pong sync.Mutex

pong.Lock() // ensure the 2nd goroutine waits &amp; the 1st goes first

go func() {
	for {
		ping.Lock()
		foo()
		pong.Unlock()
	}
}()

go func() {
	for {
		pong.Lock()
		bar()
		ping.Unlock()
	}
}()

https://go.dev/play/p/VO2LoMJ8fek

答案2

得分: 0

使用通道:

func printFoo(i int, ch chan<- bool, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Print("foo")
		ch <- true
	}()
}

func printBar(i int, ch chan<- bool, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Print("bar")
		ch <- true
	}()

}

func main() {
	times := 4
	firstchan := make(chan bool)
	secondchan := make(chan bool)
	var wg sync.WaitGroup
	for i := 0; i <= times; i++ {
		printFoo(i, firstchan, &wg)
		<-firstchan
		printBar(i, secondchan, &wg)
		<-secondchan
	}
	wg.Wait()
}

https://go.dev/play/p/MlZ9dHkUXGb

英文:

Using channel:

func printFoo(i int, ch chan&lt;- bool, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Print(&quot;foo&quot;)
		ch &lt;- true
	}()
}
func printBar(i int, ch chan&lt;- bool, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Print(&quot;bar&quot;)
		ch &lt;- true
	}()

}

func main() {
	times := 4
	firstchan := make(chan bool)
	secondchan := make(chan bool)
	var wg sync.WaitGroup
	for i := 0; i &lt;= times; i++ {
		printFoo(i, firstchan, &amp;wg)
		&lt;-firstchan
		printBar(i, secondchan, &amp;wg)
		&lt;-secondchan
	}
	wg.Wait()
}

https://go.dev/play/p/MlZ9dHkUXGb

huangapple
  • 本文由 发表于 2022年3月14日 23:50:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/71470563.html
匿名

发表评论

匿名网友

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

确定