在两个 goroutine 之间同步

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

Sync between 2 goroutines

问题

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

foobarfoobarfoobarfoobar

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

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. type ConcurrentPrinter struct {
  8. sync.WaitGroup
  9. sync.Mutex
  10. }
  11. func (cp *ConcurrentPrinter) printFoo(times int) {
  12. cp.WaitGroup.Add(times)
  13. go func() {
  14. cp.Lock()
  15. fmt.Print("foo")
  16. cp.Unlock()
  17. }()
  18. }
  19. func (cp *ConcurrentPrinter) printBar(times int) {
  20. cp.WaitGroup.Add(times)
  21. go func() {
  22. cp.Lock()
  23. fmt.Print("bar")
  24. cp.Unlock()
  25. }()
  26. }
  27. func main() {
  28. times := 10
  29. cp := &ConcurrentPrinter{}
  30. for i := 0; i <= times; i++ {
  31. cp.printFoo(i)
  32. cp.printBar(i)
  33. }
  34. time.Sleep(10 * time.Millisecond)
  35. }
英文:

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:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. type ConcurrentPrinter struct {
  8. sync.WaitGroup
  9. sync.Mutex
  10. }
  11. func (cp *ConcurrentPrinter) printFoo(times int) {
  12. cp.WaitGroup.Add(times)
  13. go func() {
  14. cp.Lock()
  15. fmt.Print(&quot;foo&quot;)
  16. cp.Unlock()
  17. }()
  18. }
  19. func (cp *ConcurrentPrinter) printBar(times int) {
  20. cp.WaitGroup.Add(times)
  21. go func() {
  22. cp.Lock()
  23. fmt.Print(&quot;bar&quot;)
  24. cp.Unlock()
  25. }()
  26. }
  27. func main() {
  28. times := 10
  29. cp := &amp;ConcurrentPrinter{}
  30. for i := 0; i &lt;= times; i++ {
  31. cp.printFoo(i)
  32. cp.printBar(i)
  33. }
  34. time.Sleep(10 * time.Millisecond)
  35. }

答案1

得分: 2

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

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

  1. var ping, pong sync.Mutex
  2. pong.Lock() // 确保第二个goroutine等待,第一个先执行
  3. go func() {
  4. for {
  5. ping.Lock()
  6. foo()
  7. pong.Unlock()
  8. }
  9. }()
  10. go func() {
  11. for {
  12. pong.Lock()
  13. bar()
  14. ping.Unlock()
  15. }
  16. }()

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:

  1. var ping, pong sync.Mutex
  2. pong.Lock() // ensure the 2nd goroutine waits &amp; the 1st goes first
  3. go func() {
  4. for {
  5. ping.Lock()
  6. foo()
  7. pong.Unlock()
  8. }
  9. }()
  10. go func() {
  11. for {
  12. pong.Lock()
  13. bar()
  14. ping.Unlock()
  15. }
  16. }()

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

答案2

得分: 0

使用通道:

  1. func printFoo(i int, ch chan<- bool, wg *sync.WaitGroup) {
  2. wg.Add(1)
  3. go func() {
  4. defer wg.Done()
  5. fmt.Print("foo")
  6. ch <- true
  7. }()
  8. }
  9. func printBar(i int, ch chan<- bool, wg *sync.WaitGroup) {
  10. wg.Add(1)
  11. go func() {
  12. defer wg.Done()
  13. fmt.Print("bar")
  14. ch <- true
  15. }()
  16. }
  17. func main() {
  18. times := 4
  19. firstchan := make(chan bool)
  20. secondchan := make(chan bool)
  21. var wg sync.WaitGroup
  22. for i := 0; i <= times; i++ {
  23. printFoo(i, firstchan, &wg)
  24. <-firstchan
  25. printBar(i, secondchan, &wg)
  26. <-secondchan
  27. }
  28. wg.Wait()
  29. }

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

英文:

Using channel:

  1. func printFoo(i int, ch chan&lt;- bool, wg *sync.WaitGroup) {
  2. wg.Add(1)
  3. go func() {
  4. defer wg.Done()
  5. fmt.Print(&quot;foo&quot;)
  6. ch &lt;- true
  7. }()
  8. }
  9. func printBar(i int, ch chan&lt;- bool, wg *sync.WaitGroup) {
  10. wg.Add(1)
  11. go func() {
  12. defer wg.Done()
  13. fmt.Print(&quot;bar&quot;)
  14. ch &lt;- true
  15. }()
  16. }
  17. func main() {
  18. times := 4
  19. firstchan := make(chan bool)
  20. secondchan := make(chan bool)
  21. var wg sync.WaitGroup
  22. for i := 0; i &lt;= times; i++ {
  23. printFoo(i, firstchan, &amp;wg)
  24. &lt;-firstchan
  25. printBar(i, secondchan, &amp;wg)
  26. &lt;-secondchan
  27. }
  28. wg.Wait()
  29. }

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:

确定