Go语言协程 | 青训营笔记

101 阅读3分钟

Go语言协程(Goroutine)

Go语言是一门支持并发编程的语言,其中最重要的特性就是协程(Goroutine)。协程是一种轻量级的线程,可以在Go语言中非常方便地创建和使用,而且可以支持大量的并发执行。

协程的创建和使用

在Go语言中,使用关键字go来启动一个协程,例如:

go func() {
	fmt.Println("Hello, Goroutine!")
}()

上面的代码就创建了一个协程,执行了一个匿名函数,输出了一句话。注意,在协程内部的代码会在一个新的协程中执行,不会阻塞当前的主协程。

协程的创建非常轻量级,可以在Go语言中创建大量的协程,例如:

for i := 0; i < 1000; i++ {
	go func() {
		fmt.Println("Hello, Goroutine!")
	}()
}

上面的代码创建了1000个协程,每个协程都执行了同样的代码。由于协程非常轻量级,可以在Go语言中创建成千上万个协程,而不会导致系统资源的浪费。

协程的通信

在并发编程中,协程之间的通信非常重要。在Go语言中,协程之间的通信可以通过通道(Channel)来实现。

通道是一种特殊的数据结构,可以用来在不同的协程之间传递数据。通道有两个主要的操作:发送(Send)和接收(Receive)。发送操作使用<-符号,接收操作使用<-符号,例如:

ch := make(chan int)

go func() {
	ch <- 42
}()

x := <-ch
fmt.Println(x)

上面的代码创建了一个整型通道ch,在一个协程中向通道发送了一个整数42,然后在主协程中从通道中接收到了这个整数,并输出了它。

通道可以用来传递任何类型的数据,包括自定义类型。通道还可以设置缓冲区大小,用来控制协程之间的同步和通信。

协程的同步

在并发编程中,协程之间的同步也非常重要。在Go语言中,可以使用同步原语来实现协程之间的同步,例如互斥锁(Mutex)和条件变量(Cond)。

互斥锁是一种常用的同步原语,可以用来保护共享资源,避免多个协程同时修改同一个变量。在Go语言中,可以使用sync.Mutex结构体来创建一个互斥锁,例如:

var mu sync.Mutex
var x int

go func() {
	mu.Lock()
	defer mu.Unlock()

	x = 42
}()

mu.Lock()
defer mu.Unlock()

fmt.Println(x)

上面的代码创建了一个互斥锁mu和一个整型变量x,在一个协程中,使用互斥锁保护变量x的写操作,然后在主协程中使用互斥锁保护变量x的读操作。

条件变量是一种可以用来等待或通知某个事件的同步原语。在Go语言中,可以使用sync.Cond结构体来创建一个条件变量,例如:

var mu sync.Mutex
var cond = sync.NewCond(&mu)
var ready bool

go func() {
	mu.Lock()
	ready = true
	cond.Signal()
	mu.Unlock()
}()

mu.Lock()
for !ready {
	cond.Wait()
}
mu.Unlock()

fmt.Println("Ready!")

上面的代码创建了一个互斥锁mu和一个条件变量cond,在一个协程中,使用互斥锁保护变量ready的写操作,并通知条件变量cond,然后在主协程中使用互斥锁和条件变量等待变量ready变为true

总结

协程是Go语言最重要的并发编程特性之一,可以方便地创建和使用,支持大量的并发执行。协程之间的通信可以通过通道来实现,而协程之间的同步可以通过同步原语来实现。在使用协程进行并发编程时,需要注意协程之间的同步和通信,避免出现竞态条件和死锁等问题。