如何使用奇数和偶数线程打印 N 个整数

问题描述 投票:0回答:4

我正在尝试从 2 个 go 例程中打印 N 个数字:

go routine odd(): 这个只能打印奇数

go routine even(): 这只能打印偶数

输出应该是: 1 2 3 4 5 6 7 8 9 10

我正在尝试使用 sync.WaitGroup 来解决这个问题。我有以下疑问:

Q1。哪种并发机制最适合这个问题?通道、等待组、互斥量等?如果您能提供相同的工作代码,那将是理想的。

Q2。为什么我无法通过以下代码正确打印序列?我做错了我无法纠正的事情。请帮助纠正。

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup
var wgO sync.WaitGroup
var wgE sync.WaitGroup

func even() {
    defer wg.Done()

    for i := 2; i <= 10; i += 2 {
        wgE.Add(1)
        wgO.Wait()
        fmt.Println(i)
        wgE.Done()
    }
}
func odd() {
    defer wg.Done()

    for i := 1; i <= 10; i += 2 {
        wgO.Add(1)
        fmt.Println(i)
        wgO.Done()
        wgE.Wait()
    }
}
func main() {
    wg.Add(2)
    go even()
    go odd()
    wg.Wait()
}
go goroutine
4个回答
2
投票

Q1。哪种并发机制最适合这个问题?通道、等待组、互斥量等?

无。您的问题与要同时完成的事情相反,没有并发机制可以帮助您。

Q2。为什么我无法通过以下代码正确打印序列?

您希望独立的 goroutines 同步运行。所以你必须打破并发。从技术上讲,这两个 goroutine 之间基于通道的乒乓球会起作用,实际上使它们不并发。你的问题没有明智的“并发”解决方案,你不会从并发性被强行破坏的残缺解决方案中学到东西。


1
投票

对@Vibhor-Dubey-InfiniteLearner 的回答进行了一些改进,因为他的回答出现了僵局

func odd(n int, syncChannel, done chan bool) {

    for i := 0; i < n; i++ {
        <-syncChannel

        if i%2 != 0 {
            fmt.Println(i)
        }

        syncChannel <- true
    }
    done <- true
}

func even(n int, syncChannel, done chan bool) {

    for i := 0; i < n; i++ {
        <-syncChannel

        if i%2 == 0 {
            fmt.Println(i)
        }

        syncChannel <- true
    }

    done <- true
}

func main() {
    done := make(chan bool)
    syncChannel := make(chan bool)
    n := 10

    go even(n, syncChannel, done)
    syncChannel <- true // This will ensure, we start at even number
    go odd(n, syncChannel, done)

    <-done
    close(syncChannel)
}

0
投票

Q1:

Which concurrency mechanism best suited for this problem?

A1:没有。您打印序号的问题不是并发的。因此,即使您实现了一个使用 Go 的并发机制(使用通道或互斥锁)的解决方案,它实际上也不会/不能并发运行,因为您想要的是 sequentially 打印您的数字。同时运行将打印数字是一个不确定的顺序。

Q2:

Why I am not able to print the sequence correctly through below code?

A2: 你的代码打印顺序不对 因为一旦 go 例程被触发,你就无法知道它们的执行顺序。所以代码:

...
go even()
go odd()
...

甚至不能保证您的

even
函数内的循环将在您的
odd
函数内的循环之前开始,即使您之前调用了
even
函数。

A2.1: 您的代码有时会出现 panic

WaitGroup is reused before previous Wait has returned
,因为
wgO.Done()
odd
函数中被调用之前
wgO.Wait()
even
函数中调用是可能的


以下是一个非常

silly 使用 sync.WaitGroup

 的实现,它说明了您的问题的解决方案如何必须打破并发才能工作。为了按顺序打印数字,我必须等待每个 go 例程的完成...

func main() { var wg sync.WaitGroup for i := 0; i <= 10; i++ { if i%2 == 0 { wg.Add(1) go func(i int) { defer wg.Done() fmt.Println(i) }(i) wg.Wait() } else { wg.Add(1) go func(i int) { defer wg.Done() fmt.Println(i) }(i) wg.Wait() } } }
我不会太在意这个问题,因为它不是学习 Go 并发机制的好例子。

在 cooursera 上有一个很好的学习 Go 并发的课程

这里


0
投票
package main import ( "fmt" "sync" "sync/atomic" ) func main() { var done int32 syncChannel := make(chan bool) // unbuffered channel. wg := new(sync.WaitGroup) wg.Add(2) go func() { // prints even numbers. defer wg.Done() for i := 0; i < 50; i += 2 { <-syncChannel fmt.Printf("Even: %d\n", i) syncChannel <- true } atomic.StoreInt32(&done, 1) }() syncChannel <- true go func() { // prints odd numbers. defer wg.Done() for i := 1; i < 50; i += 2 { <-syncChannel fmt.Printf("Odd:%d\n", i) if atomic.LoadInt32(&done) != 0 { return } syncChannel <- true } }() wg.Wait() close(syncChannel) }
参考:

https://ayada.dev/snippets/ordered-printing-with-goroutines-in-go/

© www.soinside.com 2019 - 2024. All rights reserved.