面试题答案
一键面试Go协程是什么
Go协程(goroutine)是Go语言中实现并发编程的核心机制。它类似于线程,但与传统线程不同,Go协程非常轻量级,创建和销毁的开销极小。Go协程由Go运行时(runtime)进行管理和调度,而不是操作系统内核,这使得在一个程序中可以轻松创建数以万计的协程。
它是如何实现并发的
- 调度器:Go运行时有一个内置的调度器,负责管理和调度所有的Go协程。这个调度器采用M:N调度模型,即多个Go协程(N)映射到多个操作系统线程(M)上。它可以在用户态进行调度,避免了内核态线程切换的高开销。
- 抢占式调度:Go 1.20引入了更高效的抢占式调度机制。当一个协程长时间占用CPU时,调度器可以强制暂停该协程,以便其他协程有机会执行,从而实现更公平的并发执行。
- 通道(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")
}
在上述代码中:
sync.WaitGroup
被声明为wg
。- 在启动每个协程前,调用
wg.Add(1)
,告知WaitGroup
有一个新的协程开始工作。 - 在
worker
函数中,使用defer wg.Done()
,表示该协程工作完成。 - 在
main
函数的最后,调用wg.Wait()
,此函数会阻塞,直到所有通过wg.Add(1)
添加的协程都调用了wg.Done()
,即所有协程都执行完毕。