英文:
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 (
	"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)
}
答案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 & the 1st goes first
go func() {
	for {
		ping.Lock()
		foo()
		pong.Unlock()
	}
}()
go func() {
	for {
		pong.Lock()
		bar()
		ping.Unlock()
	}
}()
答案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<- 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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论