GO语言协程创建使用并通过channel解决资源竞争

发布时间:2023-03-06 15:30

目录
  • 创建协程
  • 主协程终止,子协程也终止
  • runtime包
    • Gosched让出CPU时间片
    • Goexit立即结束当前协程
    • GOMAXPROCS设置并行CPU核数最大值,并返回之前的值
    • runtime.NumGoroutine()获取当前运行中的goroutine数量
  • 多任务资源竞争问题
    • 通过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解决资源竞争的资料请关注脚本之家其它相关文章!

        ItVuer - 免责声明 - 关于我们 - 联系我们

        本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

        桂ICP备16001015号