【Golang】协程

  好久没学习golang了,今天学习了一下协程。

文章目录

go关键字

使用go关键字,再加一个函数名,就可以开启一个新的协程.

go 复制代码
package main

import (
	"fmt"
	"time"
)

func main() {
	go func() {
		fmt.Println("goroutine")
	}()
	fmt.Println("main")
	time.Sleep(time.Second)
}

通道

  通道是协程之间的通讯机制。通过<-运算符向通道写入或读取数据。

创建通道是make函数。从通道读数据时,如果通道没有数据,就会阻塞。

以下是一个简单的例子:

go 复制代码
package main

import (
	"fmt"
	"time"
)

func worker(i int, ch chan int) {
	for {
		fmt.Println("worker", i, "通道数据", <-ch)
	}
}
func main() {
	// RoutineDemo()
	ch := make(chan int)
	// 开始3个协程
	for i := 0; i < 3; i++ {
		go worker(i, ch)
	}
	// 向通道写入数据10次
	for i := 0; i < 10; i++ {
		ch <- i
		time.Sleep(time.Second)
	}
}

等待

  在Go语言中,可以使用WaitGroup等待一组协程执行完毕。

前面的例子里,用的是time.Sleep函数,让主协程等待子协程执行完毕。这种写法肯定是不行的,因为很难准确估计子协程执行需要的时间。

幸好go语言提供了WaitGroup,可以很方便地等待所有子协程执行完毕。

go 复制代码
package main

import (
	"fmt"
	"math/rand/v2"
	"sync"
	"time"
)

func work(i int, wg *sync.WaitGroup) {
	var n = time.Duration(rand.IntN(3))
	defer wg.Done()
	time.Sleep(time.Second * n)
	fmt.Println(i, "Hello World")
}

func main() {
	wait := sync.WaitGroup{}
	for i := 0; i < 5; i++ {
		go work(i, &wait)
		wait.Add(1)
	}
	wait.Wait()
	fmt.Println("All Done")
}

互斥锁

  在Go语言中,可以使用sync.Mutex互斥锁来控制对共享资源的访问。

在下面的例子中,如果不适用互斥锁,自增的结果就会不正确。

go 复制代码
package main

import (
	"fmt"
	"sync"
)

var counter int

func increment(group *sync.WaitGroup, locker *sync.Mutex) {
	locker.Lock()
	counter++
	group.Done()
	locker.Unlock()
}
func main() {

	var lock sync.Mutex
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go increment(&wg, &lock)
	}

	wg.Wait()
	fmt.Println(counter)
}

  去掉互斥锁,我得到的结果是991,而不是1000。

选择器

  Go语言中的select关键字可以用来监听通道上的数据流动。

当通道上有数据流入时,对应的case会被执行。如果没有数据流入,默认的代码会被执行。

比如说主协程可以监听多个通道,每个子协程向不同的通道写入数据。以下是一个简单的例子:

go 复制代码
package main

import (
	"fmt"
	"time"
)

func main() {

	ch1 := make(chan string)
	ch2 := make(chan string)

	go func() {
		for {
			time.Sleep(1 * time.Second)
			ch1 <- "hello"
		}
	}()

	go func() {
		for {
			time.Sleep(2 * time.Second)
			ch2 <- "world"
		}
	}()
	for {
		select {
		case msg1 := <-ch1:
			fmt.Println("msg1", msg1)
		case msg2 := <-ch2:
			fmt.Println("msg2", msg2)
		}
	}
}
相关推荐
dialect_1 小时前
KMP算法
开发语言·c++·算法
总要学点什么2 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
深蓝AI3 小时前
Python 3.13 的 Queue.shutdown:异步消费者终于能正常收工了
后端
武子康3 小时前
MultiNet6 空闲崩溃:`EXCVADDR=0x8` 后又出现 `CORRUPT HEAP`
人工智能·后端·agent
开开心心_Every3 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
chenbingjie_c4 小时前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++
吴卫斌4 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
武子康4 小时前
MultiNet7 每轮都 clean,ESP32-P4 内存为什么还在掉?
人工智能·后端·agent
超级架构师5 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
陈随易5 小时前
AI 运维服务器,安全又可靠的方法
前端·后端·程序员