并发编程
并发VS并行
并发(concurrency)
把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。
并行(parallelism)
把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。
协程-Goroutine
协程:用户态、轻量级线程、栈KB级别
线程:内核态、一个线程可以跑多个协程、栈MB级别
使用协程
func Hello(i int) {
fmt.Println("Hello:" + fmt.Sprint(i))
}
func main() {
for i := 0; i < 5; i++ {
//开启协程
go func(j int) {
Hello(j)
}(i)
}
//使用定时阻塞
time.Sleep(time.Second)
}
协程通信
官方推荐使用通道通信
通道-channel
通道(channel)是用来传递数据的一个数据结构。
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
// 通道关闭之前会进行阻塞等待的操作
func CalSquare() {
//创建无缓冲的通道
src := make(chan int)
//创建有缓冲的通道
dest := make(chan int, 3)
go func() {
//关闭通道传输
defer close(src)
for i := 0; i < 10; i++ {
//存入数据
src <- i
}
}()
go func() {
//关闭通道传输
defer close(dest)
//取出数据
for i := range src {
//存入数据
dest <- i * i
}
}()
//取出数据
for i := range dest {
fmt.Println(i)
}
}
func main() {
CalSquare()
}
并发安全-Lock锁
在并发编程中,锁(Lock)是用来保护共享资源的一种机制。在Go语言中,锁是实现并发的重要工具之一。它可以确保在多个协程中同时访问共享资源时,只有一个协程能够读取或修改这些资源。本文将介绍Go语言中锁的使用方法,帮助读者更好地理解并发编程。
//并发安全(Lock)
var (
x int64
//使用Lock
x_Lock sync.Mutex
)
func AddWithLock() {
for i := 0; i < 2000; i++ {
//上锁
x_Lock.Lock()
x += 1
//开锁
x_Lock.Unlock()
}
}
func AddWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go AddWithoutLock()
}
time.Sleep(time.Second)
fmt.Println("AddWithoutLock:", x)
x = 0
for i := 0; i < 5; i++ {
go AddWithLock()
}
time.Sleep(time.Second)
fmt.Println("AddWithLock:", x)
}
func main() {
Add()
}
WaitGroup的使用
用来阻塞主协程,可以等待所有协程执行完。
总共三个方法
Add(n)【n为总共要等待的协程数】
Done【在协程中调,相当于Add(-1)】
Wait【等待阻塞结束】
func Many() {
var wg sync.WaitGroup
//添加协程数量
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
//协程数量减一
defer wg.Done()
fmt.Println("hello:" + fmt.Sprint(j))
}(i)
}
//阻塞等待协程结束
wg.Wait()
}
func main() {
Many()
}