Java程序员_编程开发学习笔记_网站安全运维教程_渗透技术教程

Go语言goroutine相关教程

阿贵
1月29日发布 /正在检测是否收录...
温馨提示:
本文最后更新于2025年01月29日,已超过80天没有更新,若内容或图片失效,请留言反馈。

Go语言中的goroutine是一种轻量级的执行单元,它使得并发编程变得更加简单和高效。Goroutine可以看作是用户态下的线程,但它们比操作系统提供的线程更加轻量级,创建和销毁的开销非常小,因此可以在一个程序中轻松地创建成千上万个goroutine 。

Goroutine的基本使用

要启动一个新的goroutine,只需要在函数调用前加上go关键字。例如:

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world") // 启动一个新的goroutine来执行say函数
    say("hello")    // 主goroutine继续执行say函数
}

在这个例子中,say("world")会在新的goroutine中运行,而主goroutine会继续执行say("hello")。由于两个goroutine并行运行,所以输出可能会交错出现。

Goroutine与Channel通信

为了安全地在多个goroutine之间进行数据交换或同步操作,Go提供了channel类型。通过channel,goroutine可以发送和接收数据,从而实现相互之间的通信和同步。下面是一个简单的例子,展示了如何使用channel来进行goroutine间的通信:

package main

import (
    "fmt"
)

func sum(a []int, c chan int) {
    total := 0
    for _, v := range a {
        total += v
    }
    c <- total // 将总和发送到channel
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}
    c := make(chan int)
    go sum(a[:len(a)/2], c) // 分割数组并启动goroutine计算部分和
    go sum(a[len(a)/2:], c)
    x, y := <-c, <-c // 从channel接收两个总和
    fmt.Println(x, y, x+y)
}

Goroutine调度器

Go语言的运行时系统负责管理goroutine的调度。调度器会自动分配goroutine到可用的逻辑处理器(P)上,并且在这些处理器之间移动goroutine以确保公平性和效率。每个逻辑处理器通常绑定到一个操作系统线程上,这有助于减少上下文切换的开销 。

Goroutine的栈是动态增长的,这意味着它们可以根据需要分配更多的内存空间,这对于递归调用或者处理大型数据结构特别有用。此外,Go的调度器还支持抢占式调度,确保长时间运行的任务不会独占CPU资源 。

使用Goroutine的最佳实践

尽管goroutine非常强大,但在使用时也需要遵循一些最佳实践,比如:

  • 不要创建不知道何时退出的goroutine 。
  • 避免在库函数内部擅自启动goroutine,应该让调用者决定是否并发执行 。
  • 当主goroutine退出时,所有的其他goroutine也会被终止,因此如果希望保持程序运行直到所有goroutine完成工作,需要适当同步,例如使用sync.WaitGroup

总之,goroutine是Go语言并发模型的核心,它结合了通道(channel),提供了一种简洁、高效的方式来编写并发程序。通过合理利用goroutine和channel,开发者可以构建出既易于理解和维护,又能够充分利用多核处理器性能的应用程序。

喜欢就支持一下吧
点赞 0 分享 收藏
评论 抢沙发
OωO
取消 登录评论