【问题标题】:Why don't the GO routines start?为什么 GO 例程不启动?
【发布时间】:2023-04-09 05:16:01
【问题描述】:

我写了一个简单的 GO 程序,它应该启动 3 个 GO 例程。但是,GO 例程没有启动。

请注意,情况与本文中的描述者不同:

Why is my goroutine not executed?

程序应该等待 GO 例程结束执行......因此,程序应该永远等待(因为例程永远不会停止)。

package main

import (
    "fmt"
    "net"
    "os"
    "time"
    "sync"
)

func main() {

    wg := sync.WaitGroup{}

    fmt.Print("Starting 3 clients\n")

    for i:=0; i<3; i++ {

        client := func(inName string) {

            fmt.Printf("Client <%s> started\n", inName)

            wg.Add(1)
            conn, err := net.Dial("tcp", ":8000")
            if err != nil {
                fmt.Printf("[%s] Error while connecting to the server: %s", inName, err.Error())
                os.Exit(1)
            }

            n := 0
            sleepDuration, _ := time.ParseDuration("2s")
            for {
                message := fmt.Sprintf("[%s] > message %d\n", inName, n)
                fmt.Printf("%s", message)
                _, err := conn.Write([]byte(message))
                if nil != err {
                    fmt.Sprintf("[%s] Error while writing data to the socket: %s", inName, err.Error())
                    os.Exit(1)
                }
                time.Sleep(sleepDuration)
                n++
            }
        }

        name := fmt.Sprintf("Client%d", i)
        fmt.Printf("Starting client <%s>...\n", name)
        go client(name)
        fmt.Print("Done\n")
    }

    wg.Wait()
}

结果:

Starting 3 clients
Starting client <Client0>...
Done
Starting client <Client1>...
Done
Starting client <Client2>...
Done

【问题讨论】:

  • 必须从goroutine的外部调用wg.Add(1)。否则 wg.Wait() 可能不会(在您的情况下:没有)看到 Add(1)。
  • wg.Add(1) 放入 goroutine 是一种竞争条件。当调用wg.Wait() 时,您不知道那些Add 是否已被执行。你忘了在 goroutine 中调用 Done()
  • 好的,我明白了。这个工具充当一个简单的计数器。谢谢。
  • @DenisKertios 给出的答案是否解决了您的问题?如果是,你可以接受。

标签: go


【解决方案1】:

正如this 解决方案所说:

重要的是 wg.Add() 发生在 go 语句之前 防止竞争条件。以下也是正确的:

因此,您需要在 go 例程本身中取出 wg.Add(1) 并在启动 go 例程之前调用它。另外,在函数开始时调用defer wg.Done(),这样,WaitGroup 计数器就会减一。看看下面的代码。

package main

import (
    "fmt"
    "net"
    "os"
    "time"
    "sync"
)

func main() {

    wg := sync.WaitGroup{}

    fmt.Print("Starting 3 clients\n")

    for i:=0; i<3; i++ {

        client := func(inName string) {

            defer wg.Done() // added this line

            fmt.Printf("Client <%s> started\n", inName)

            conn, err := net.Dial("tcp", ":8000")
            if err != nil {
                fmt.Printf("[%s] Error while connecting to the server: %s", inName, err.Error())
                os.Exit(1)
            }

            n := 0
            sleepDuration, _ := time.ParseDuration("2s")
            for {
                message := fmt.Sprintf("[%s] > message %d\n", inName, n)
                fmt.Printf("%s", message)
                _, err := conn.Write([]byte(message))
                if nil != err {
                    fmt.Sprintf("[%s] Error while writing data to the socket: %s", inName, err.Error())
                    os.Exit(1)
                }
                time.Sleep(sleepDuration)
                n++
            }
        }

        name := fmt.Sprintf("Client%d", i)
        fmt.Printf("Starting client <%s>...\n", name)
        wg.Add(1) // moved this line
        go client(name)
        fmt.Print("Done\n")
    }

    wg.Wait()
}

【讨论】:

    猜你喜欢
    • 2017-12-06
    • 2011-06-03
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 2018-07-13
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多