GO语言协程创建使用并通过channel解决资源竞争
作者:Jeff的技术栈
这篇文章主要为大家介绍了GO语言协程创建使用并通过channel解决资源竞争,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
创建协程
goroutine是go的设计核心,就是协程
主协程终止了,子协程也终止
package main import ( "fmt" "time" ) func newTask() { for { fmt.Println("this is a newTask") time.Sleep(time.Second) //延时1s } } func main() { go newTask() //新建一个协程, 新建一个任务 for { fmt.Println("this is a main goroutine") time.Sleep(time.Second) //延时1s } }
主协程终止,子协程也终止
package main import ( "fmt" "time" ) //主协程退出了,其它子协程也要跟着退出 func main() { go func() { i := 0 for { i++ fmt.Println("子协程 i = ", i) time.Sleep(time.Second) } }() //别忘了() i := 0 for { i++ fmt.Println("main i = ", i) time.Sleep(time.Second) if i == 2 { break } } }
runtime包
Gosched让出CPU时间片
等待其他协程执行完
runtime.Gosched()用于让出CPU时间片,让出当前goroutine(协程)的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。
类似:接力赛,A跑了一会碰到代码runtime.Gosched()就把接力棒交给B,A歇着,B继续跑
案例:
package main import ( "fmt" "runtime" ) func main() { go func() { for i := 0; i < 5; i++ { fmt.Println("go") } }() for i := 0; i < 2; i++ { //让出时间片,先让别的协议执行,它执行完,再回来执行此协程 runtime.Gosched() fmt.Println("hello") } } go go go go go hello hello
Goexit立即结束当前协程
runtime.Goexit() //立即结束当前协程
案例:
package main import ( "fmt" "runtime" ) func test() { defer fmt.Println("ccccccccccccc") //return //终止此函数 runtime.Goexit() //终止所在的协程 fmt.Println("dddddddddddddddddddddd") } func main() { //创建新建的协程 go func() { fmt.Println("aaaaaaaaaaaaaaaaaa") //调用了别的函数 test() fmt.Println("bbbbbbbbbbbbbbbbbbb") }() //别忘了() //特地写一个死循环,目的不让主协程结束 for { } } aaaaaaaaaaaaaaaaaa ccccccccccccc
GOMAXPROCS设置并行CPU核数最大值,并返回之前的值
runtime.GOMAXPROCS() //设置并行CPU核数最大值,并返回之前的值
package main import ( "fmt" "runtime" ) func main() { //n := runtime.GOMAXPROCS(1) //指定以1核运算 n := runtime.GOMAXPROCS(2) //指定以8核运算 fmt.Println("n = ", n) for { go fmt.Print(1) fmt.Print(0) } }
runtime.NumGoroutine()获取当前运行中的goroutine数量
先介绍一个最简单的监控方式。
通过 runtime.NumGoroutine() 获取当前运行中的 goroutine 数量,通过它确认是否发生泄漏。
func main() { go test() go test() go test() go test() a:=runtime.NumGoroutine() fmt.Println(a) // 5 for { } }
多任务资源竞争问题
package main import ( "fmt" "time" ) //定义一个打印机,参数为字符串,按每个字符打印 //打印机属于公共资源 func Printer(str string) { for _, data := range str { fmt.Printf("%c", data) time.Sleep(time.Second) } fmt.Printf("\n") } func person1() { Printer("hello") } func person2() { Printer("world") } func main() { //新建2个协程,代表2个人,2个人同时使用打印机 go person1() go person2() //特地不让主协程结束,死循环 for { } }
通过channel解决资源竞争问题
package main import ( "fmt" "time" ) //全局变量,创建一个channel var ch = make(chan int) //定义一个打印机,参数为字符串,按每个字符打印 //打印机属于公共资源 func Printer(str string) { for _, data := range str { fmt.Printf("%c", data) time.Sleep(time.Second) } fmt.Printf("\n") } //person1执行完后,才能到person2执行 func person1() { Printer("hello") ch <- 666 //给管道写数据,发送 } func person2() { <-ch //从管道取数据,接收,如果通道没有数据他就会阻塞 Printer("world") } func main() { //新建2个协程,代表2个人,2个人同时使用打印机 go person1() go person2() //特地不让主协程结束,死循环 for { } }
主协程如何等其余协程完再退出
var wg sync.WaitGroup wg.Add(2) //任务数 wg.Done() //结束 wg.Wait() //等待 package main import ( "fmt" "sync" ) var wg sync.WaitGroup func main() { wg.Add(2) out := producer() consumer(out) defer fmt.Println("主线程结束") wg.Wait() //等待 } //此通道只能写,不能读 func producer() chan interface{} { ch := make(chan interface{}) go func() { for i := 0; i < 5; i++ { ch <- fmt.Sprintf("协程1-%d", i) //写入字符串 } defer close(ch) wg.Done() //结束 }() return ch } //此channel只能读,不能写 func consumer(data chan interface{}) { defer fmt.Println("读取结束") go func() { for num := range data { fmt.Println(num) } wg.Done() //结束 }() }
以上就是GO语言协程创建使用并通过channel解决资源竞争的详细内容,更多关于GO语言协程channel解决资源竞争的资料请关注脚本之家其它相关文章!