go语言进阶
1.并发与并行
go可以充分发挥多核优势,高效运行
1-1 goroutine
goroutine 是 Go 语言中的并发执行单元。它由 Go 运行时调度器管理,不依赖于操作系统线程的直接调度。每个 goroutine 都是由 Go 运行时管理的,它们是独立的执行流,在同一线程或多个线程上运行。
线程与协程
一个异步例子
package main
import "fmt"
func sayHello() {
fmt.Println("Hello from Goroutine!")
}
func main() {
for a := 0; a < 10; a++ {
go sayHello() // 创建并启动一个 goroutine
}
fmt.Println("Hello from Main!")
}
要创建一个 goroutine,只需要使用 go 关键字,后面跟上一个函数调用。这样,Go 运行时会异步地执行这个函数,而不会阻塞当前的执行流程。
在上面的代码中,go sayHello() 会启动一个新的 goroutine 执行 sayHello 函数,而 main 函数中的 fmt.Println 会立即执行。所以for里面十次并行的函数还没运行完,main函数就结束了,sayhello函数没有被运行10次。如果去掉前面的go,则程序一步一步运行sayhello函数成功运行十次。通过通信共享内存
1-3Channel
首先明白有缓冲通道和无缓冲通道
无缓冲通道,也称为同步通道,在传输数据时,发送方和接收方必须在同一时刻进行配对操作,才能成功地进行数据传输。换句话说,数据只有在有接收者准备好接收时,发送者才能将数据发送出去,反之亦然。
缓冲通道在其内部有一个缓冲区,可以存储一定数量的数据。在发送数据时,发送方不需要等待接收方立即接收数据,只要缓冲区没有满,发送操作就会立即成功。而接收方则可以在稍后的时间内从通道中取出数据。如果缓冲区为空,接收方就会阻塞直到有数据可用
区别
无缓冲通道make(chan int)
ch := make(chan int) // 创建无缓冲通道
// 发送数据
go func() {
ch <- 42 // 发送数据到通道,发送会阻塞,直到有接收者准备好
}()
// 接收数据
val := <-ch // 接收数据,这也会阻塞,直到有发送者发送数据
fmt.Println(val) // 输出:42
有缓冲通道make(chan int, 2)
ch := make(chan int, 2) // 创建一个缓冲区大小为2的通道
// 发送数据
ch <- 1 // 不会阻塞
ch <- 2 // 不会阻塞
// 当缓冲区已满时,以下发送操作会被阻塞
ch <- 3 // 会阻塞,直到接收者消费数据
// 接收数据
val := <-ch // 从缓冲区接收数据
fmt.Println(val) // 输出:1
1-4并发安全Lock
锁的目的是防止多个线程(或进程)同时访问共享资源(如内存、文件、数据库等),导致数据不一致。通过锁,程序可以确保某个共享资源在同一时刻只有一个线程能够访问,其他线程则需要等待。
1-5waitgroup
有多个并发任务(比如多个 HTTP 请求),并希望在所有任务完成后进行某些操作,
由于不知道多线程要运行多久,所以使用 WaitGroup 来等待所有并发任务完成