创建协程
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解决资源竞争的资料请关注编程网其它相关文章!