【问题标题】:How to print N integers using odd and even thread如何使用奇偶线程打印 N 个整数
【发布时间】:2021-10-15 23:26:33
【问题描述】:

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

goroutine odd():这只能打印奇数

goroutine even():这只能打印偶数

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

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

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

第二季度。为什么我无法通过以下代码正确打印序列?我做错了我无法纠正的事情。请帮忙改正。

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()
}

【问题讨论】:

  • 不是专业人士,但我认为您列出的那些并发机制不是相互独立的,也不是相互排斥的。 Waitgroup 需要等待,直到 go 例程完成。需要通道来允许 go 例程和正常功能之间的通信。如果多个 go 例程访问相同的资源,互斥锁可以避免竞争条件。
  • 并发的整个理念并发独立的执行流。使用并发来为您的问题建模是错误,您不会学到任何东西。基本上不可能做你想做的事:你必须强制你的 goroutines un并发。
  • 如果输出需要有序,并发是错误的模型。
  • @Adrian:应该用什么来代替上述问题?你能推荐一下吗?
  • 令人费解的你可能写过play.golang.org/p/XYPnLEe0KrW

标签: go goroutine


【解决方案1】:

第一季度。哪种并发机制最适合这个问题?通道、等待组、互斥锁等?

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

第二季度。为什么我无法通过下面的代码正确打印序列?

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

【讨论】:

    【解决方案2】:

    Q1:Which concurrency mechanism best suited for this problem?

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

    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:您的代码有时会出现紧急情况WaitGroup is reused before previous Wait has returned,因为在 even 函数内部调用 wgO.Wait() 之前,可能会调用 wgO.Done() 内部的 odd 函数.


    以下是使用sync.WaitGroup 的非常愚蠢的实现,它说明了解决问题的方法必须如何破坏并发才能工作。为了按顺序打印数字,我必须等待每个 goroutine 完成...

    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 的并发性here

    【讨论】:

    • 感谢@Rafael FT 的详细解释。即使我得到了这么多负面的反对票,我觉得这个问题仍然会帮助许多其他对并发有同样误解的人......他们会明白何时以及何时不应用并发机制:)
    猜你喜欢
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 1970-01-01
    相关资源
    最近更新 更多