MST

星途 面试题库

面试题:Go中Go协程与并发的基础理解

请解释Go协程是什么,以及它是如何实现并发的?在一个简单的Go程序中,如何创建多个Go协程并等待它们全部执行完毕?
48.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

Go协程是什么

Go协程(goroutine)是Go语言中实现并发编程的核心机制。它类似于线程,但与传统线程不同,Go协程非常轻量级,创建和销毁的开销极小。Go协程由Go运行时(runtime)进行管理和调度,而不是操作系统内核,这使得在一个程序中可以轻松创建数以万计的协程。

它是如何实现并发的

  1. 调度器:Go运行时有一个内置的调度器,负责管理和调度所有的Go协程。这个调度器采用M:N调度模型,即多个Go协程(N)映射到多个操作系统线程(M)上。它可以在用户态进行调度,避免了内核态线程切换的高开销。
  2. 抢占式调度:Go 1.20引入了更高效的抢占式调度机制。当一个协程长时间占用CPU时,调度器可以强制暂停该协程,以便其他协程有机会执行,从而实现更公平的并发执行。
  3. 通道(Channel):Go协程之间通过通道进行通信和同步。通道是类型化的管道,可以在协程之间传递数据,通过在通道上进行发送和接收操作来实现协程之间的同步和数据共享,避免了传统并发编程中共享内存带来的复杂同步问题(如锁争用、死锁等)。

在简单Go程序中,创建多个Go协程并等待它们全部执行完毕的方法

可以使用sync.WaitGroup来实现。sync.WaitGroup是Go标准库中用于等待一组协程完成的工具。 以下是示例代码:

package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    // 模拟工作
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup
    numWorkers := 3

    for i := 1; i <= numWorkers; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers have finished")
}

在上述代码中:

  1. sync.WaitGroup被声明为wg
  2. 在启动每个协程前,调用wg.Add(1),告知WaitGroup有一个新的协程开始工作。
  3. worker函数中,使用defer wg.Done(),表示该协程工作完成。
  4. main函数的最后,调用wg.Wait(),此函数会阻塞,直到所有通过wg.Add(1)添加的协程都调用了wg.Done(),即所有协程都执行完毕。