GO程复习---关于goroutine和channel

一、Go程

1.实现go程

go程的实现十分简单,只需要在该函数前加上关键字go,即可成为一个gotoutine

package main

import "fmt"

func goRoutine1(){
	fmt.Println("11111111111111111")
}
func goRoutine2(){
	fmt.Println("2222222222222222")
}

func main() {
	go goRoutine1()
	go goRoutine2()
	fmt.Println("main")
	for {
		;
	}
}

2.runtime.Gosched

用于让出CPU时间片,让出当前goroutine的执行权限,调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行。这就像跑接力赛,A跑了一会碰到代码runtime.Gosched()就把接力棒交给B了,A歇着了,B继续跑。简单来说 就是,调用runtime.Gosched的go程,执行效率变低  ,其他程序执行变快。

runtime.Gosched()

3.GOexit

调用此函数会立即使当前的goroutine的运行终止(终止协程),而其它的goroutine并不会受此影响。runtime.Goexit在终止当前goroutine前会先执行此goroutine的还未执行的defer语句。请注意千万别在主函数调用runtime.Goexit,因为会引发panic。

runtime.Goexit()

4.runtime.GOMAXPROCS()

用来设置可以并行计算的CPU核数最大值,并返回之前的值。默认此函数的值与CPU逻辑个数相同,即有多少个goroutine并发执行,当然可以设置它,它的取值是1~256。最好在主函数在开始前设置它,因为设置它会停止当前程序的运行。GO默认是使用一个CPU核的,除非设置runtime.GOMAXPROCS。那么在多核环境下,什么情况下设置runtime.GOMAXPROCS会比较好的提高速度呢?适合于CPU密集型、并行度比较高的情景。如果是IO密集型,CPU之间的切换也会带来性能的损失。

 n := runtime.GOMAXPROCS(4)
//n为上一次调用时的核数  首次为默认值1

runtime包其他功能如垃圾回收等,请参考完整说明 :https://studygolang.com/articles/13994?fr=sidebar

二、channel

channel 可以把它看成一个管道,是 goroutine 之间通信的一种方式。

channel 创建

ch := make(chan TYPE CAPCITY)

CAPCITY==0   -->  无缓冲阻塞channel
CAPCITY > 0  -->  有缓冲无阻塞channel
//ch:=make(chan int,3)

 channel读写

ch := make(chan int)

// write to channel
ch <- x

// read from channel
x <- ch

// another way to read
x = <- ch

利用无缓冲channel阻塞的特点,可以实现go程之间顺序的控制 

在主函数中定义一个无缓冲channel,在主函数中进行读channel操作,在go程逻辑执行完以后进行写channel操作,即可实现主函数等待所以go程执行完以后再退出。

package main

import (
	"fmt"
	"runtime"
)

func goRoutine1(ch chan int){
	ch <- 1
	for i:=0;i<10;i++{
		fmt.Println("111111111111111111111111111111")
	}
}
func goRoutine2(ch chan int){
	x:=<-ch
	fmt.Printf("chennel %d  ---------------\n",x)
	for i:=0;i<10;i++{
		if i==5{
			runtime.Goexit()
		}
		fmt.Println("2222222222222222")
	}
}

func main() {
	ch:=make(chan int)
	go goRoutine1(ch)
	go goRoutine2(ch)
	for i:=0;i<10;i++{
		runtime.Gosched()
		fmt.Println("main");
	}
}
//先执行完goroutine1 再执行goroutine2

channel长度

//chennl中剩余未读取的个数
len(ch) 

//chennl长度
caps(ch)

无缓冲channel中len和caps为0

关闭 channel

ch := make(chan int)

close(ch)
package main

import (
	"fmt"
	"runtime"
)

func goRoutine1(ch chan int){
	for i:=0;i<10;i++{
		ch<-i
	}
	close(ch)
}
func main() {
	ch:=make(chan int)
	go goRoutine1(ch)
	for{
		if num,ok:=<-ch;ok==true{
			fmt.Println(num)
		}else {
			break;
		}
	}

}



//或者
for num:=range ch{
		fmt.Println(num)
	}

单向channel

var ch1 chan<- int
var ch2 <-chan int

配合 select 使用

select 用法类似与 IO 多路复用,可以同时监听多个 channel 的消息状态,看下面的例子

select {
    case <- ch1:
    ...
    case <- ch2:
    ...
    case ch3 <- 10;
    ...
    default:
    ...
}

你可能感兴趣的:(golang知识)