GO-协程goroutine

1.创建协程

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
	}
}

2.主协程终止,子协程也终止

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
		}
	}

}

3.runtime包

3.1 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

3.2 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

3.3 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)
	}
}

3.4 runtime.NumGoroutine()获取当前运行中的goroutine数量

	先介绍一个最简单的监控方式。
	通过 runtime.NumGoroutine() 获取当前运行中的 goroutine 数量,通过它确认是否发生泄漏。

func main() {

 go test()
 go test()
 go test()
 go test()

 a:=runtime.NumGoroutine()
 fmt.Println(a) // 5
 for  {
  
 }
}

4.多任务资源竞争问题

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 {

	}
}

5.通过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 {

	}
}

6.主协程如何等其余协程完再退出

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() //结束
	}()

}

7.安全的goroutine-threading包

什么是安全的goroutine?处理好了错误,threading包

package main

import (
	"fmt"

	"github.com/zeromicro/go-zero/core/threading"
)

func main() {
	threading.GoSafe(test)
}

func test() {
	fmt.Println("111")
}

7.1 threading源码

//处理了rescue.Recover(

func GoSafe(fn func()) {
	go RunSafe(fn)
}

func RunSafe(fn func()) {
	defer rescue.Recover()

	fn()
}
posted @ 2020-11-16 15:52  Jeff的技术栈  阅读(252)  评论(0编辑  收藏  举报
回顶部