瑶风 2024-07-04 10:15 采纳率: 33.3%
浏览 17

go main子协程嵌套子协程,main结束后子协程的子协程可能不结束

以下代码表现不一致:执行时有概率只输出Main func,有概率输出Main func datais:user_new_an datais:user_an

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func testNewName() {
    defer wg.Done()
    time.Sleep(10)
    test := "user_new_an"
    res := fmt.Sprintf("datais:%s", test)
    fmt.Println(res)
}
func testName() error {
    test := "user_an"
    wg.Add(1)
    go testNewName()
    wg.Wait()
    res := fmt.Sprintf("datais:%s", test)
    fmt.Println(res)
    return nil
}
func main() {
    go func() {
        err := testName()
        if err != nil {
            fmt.Println("err")
        }
    }()
    fmt.Println("Main func")
    time.Sleep(1)
}


同理,以下代码也是概率性的:

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func testNewName() {
    defer wg.Done()
    time.Sleep(10)
    test := "user_new_an"
    res := fmt.Sprintf("datais:%s", test)
    fmt.Println(res)
}
func testName() error {
    test := "user_an"
    wg.Add(1)
    go testNewName()
    wg.Wait()
    res := fmt.Sprintf("datais:%s", test)
    fmt.Println(res)
    return nil
}
func main() {
    go func() {
        err := testName()
        if err != nil {
            fmt.Println("err")
        }
    }()
    fmt.Println("Main func")
    time.Sleep(1)
}


究竟为什么呢?我理解main方法结束后,嵌套的子协程会立即结束,但是从表现上看,子协程再嵌套的子协程有概率不会结束,有什么理论依据或者文档么?究竟怎么解释这种现象?

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-07-04 10:15
    关注

    引自免费微信小程序:皆我百晓生

    你的理解基本正确,在 Go 语言中,当 main 函数结束时,所有的 goroutine(协程)都会被终止,不论它们是否已经完成其任务。但是,这里的关键在于 Go 的调度器如何处理并发执行的 goroutine。Go 的调度器是协作式多任务调度器,这意味着它需要 goroutine 的主动配合来切换执行流程。在你的代码中,主 goroutine 在执行完其主要任务后立即结束,而并未等待所有子协程(goroutine)完成。这可能导致尚未完成的任务被终止。同时,由于 Go 的调度策略,如果主协程退出得太快,可能会错过某些子协程的完成机会。因此,你观察到的现象可能是由于主协程过早结束导致的。

    关于你的两个代码片段,它们的行为可能受到操作系统调度和Go运行时调度策略的影响,特别是当有大量的并发goroutine时,有可能在主goroutine结束之前一些子goroutine并未完成执行。此外,由于Go的并发模型是基于非阻塞I/O和协程的协作调度,因此goroutine的执行可能会受到其他正在运行的goroutine的影响。这些因素都可能导致你观察到的行为不一致性。

    关于你提到的理论依据或文档,你可以查阅 Go 的并发模型和 Goroutine 的相关文档。特别是关于 Goroutine 的生命周期和调度策略的部分,这将有助于你理解为什么子协程可能在主协程结束后未完全执行完。此外,也可以查阅关于操作系统进程调度的相关文档,这将有助于你理解操作系统如何管理并发执行的任务。不过,对于具体行为的解释可能还需要结合具体的环境和代码实现。建议你可以通过添加更多的同步机制(如使用 channel 进行同步)来确保子协程在主协程结束前完成其任务。另外需要注意Go运行时(runtime)中的一些并发模型的行为也可能影响到结果的表现。因此,在编写涉及复杂并发模式的代码时,理解和测试其行为是非常重要的。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月4日