Go   发布时间:2022-04-13  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Go基础知识梳理(四)大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

Go基础知识梳理(四)

@H_801_3@GO的哲学是“不要通过共享内存来通信,而是通过通信来共享内存”,通道是GO通过通信来共享内存的载体。

rumtime包常用方法

runtime.NumGoroutIne() //返回当前程序的协程数量
runtime.GOMAXPROCS(0) //获取当前的GOMAXPROCS数量
runtime.GOMAXPROCS(2) //设置程序的GOMAXPROCS数量为2

goroutIne

@H_801_3@特性

  • 执行是非阻塞的,不会等待
  • go 后面的返回值会被忽略
  • 调度器不能保证goroutIne的执行顺序
fun main() {
    //另起一个协程去打印
    go func() {
        fmt.Println("gorunTine") 
    }()
}
@H_197_28@chan
//创建chan
c := make(chan dataTypE)
//无缓冲, len 和 cap 都是0
fmt.Println(len(C)) //0
fmt.Println(cap(C)) //0


//有缓冲
c = make(chan dataType, 10)
//len 代表没有被读取的元素数, cap 代表整个通道的容量
fmt.Println(len(C)) //0
fmt.Println(cap(C)) //10

WaiTingGroup组件

@H_801_3@Add(10) 给内置计数器加10
Done() 相当于Add(-1)
Wait() 内置计数器不为0则一直等待

// 写法
func main() {
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func(i int) {
			defer wg.Done()
			fmt.Println(i)
			time.Sleep(time.Millisecond * 3000)
		}(i)
	}
	wg.Wait()
	fmt.Println("done")
}

SELEct

  1. 先打乱所有的case语句
  2. 遍历case语句,查看是否已经读写了
  3. 选择可读写的case去执行
  4. 没有可读写的case,则查看default语句是否定义,再去执行
  5. 没有defaul语句,则会等待可执行的case
@H_801_3@看一段融合了并发,缓冲,退出通知等多重特性的代码

func GenerateA(done chan struct{}) chan int {
	ch := make(chan int, 5)
	// fmt.Println("通道数+1")
	go func() {
		fmt.Println("线程数+A")
	Label:
		for {
			SELEct {
			case res := <-done:
				fmt.Println("done", res)
				break Label
			case ch <- rand.Int():
			}

		}
		close(ch)
	}()
	return ch
}
func GenerateB(done chan struct{}) chan int {
	ch := make(chan int, 5)
	go func() {
		fmt.Println("线程数+B")
	Label:
		for {
			SELEct {
			case res := <-done:
				fmt.Println("done", res)
				break Label
			case ch <- rand.Int():
			}
		}
		close(ch)
	}()
	return ch
}

func GenerateInt(done chan struct{}) chan int {
	//无缓冲通道
	ch := make(chan int)
	send := make(chan struct{})
	go func() {
	Label:
		for {

			SELEct {
			case <-done:
				send <- struct{}{}
				send <- struct{}{}
				break Label
			case ch <- <-GenerateA(send):
				fmt.Println("chose A")
			case ch <- <-GenerateB(send):
				fmt.Println("chose B")
			}
		}
		close(ch)
	}()
	return ch
}

func main() {
	done := make(chan struct{})
	ch := GenerateInt(donE)
	fmt.Println(runtime.NumGoroutIne())
	for i := 0; i < 10; i++ {
		fmt.Println(<-ch)
	}
	fmt.Println(runtime.NumGoroutIne())
	done <- struct{}{}
	fmt.Println("stop gernate", struct{}{})
	time.Sleep(1 * time.Second) //等待1s,让停止的goruntime打印,如果不加这句话,可能会导致主线程比新起的协程早退出,从而无法打印出done {}
}
@H_801_3@打印结果不展示,其中发现的问题:
1.打印出来的数字长度不固定
2.每次SELEct查看case是否堵塞的时候,都会执行一次该方法

Context

func main() {
	ctxa, cancel := context.WithCancel(context.BACkground())
	go work(ctxa, "work1")
	tm := time.Now().Add(3 * time.Second)
	ctxb, _ := context.WithDeadline(ctxa, tm)
	go work(ctxb, "work2")
	oc := OtherContext{Ctxb}
	ctxc := context.WithValue(oc, "key", "andes, pass from main")
	go workWithValue(ctxc, "work3")
	time.Sleep(10 * time.Second)
	cancel()
	time.Sleep(5 * time.Second)
	fmt.Println("main stop")

}

type OtherContext struct {
	context.Context
}

func work(ctx context.Context, name String) {
	for {
		SELEct {
		case <-ctx.Done():
			fmt.Printf("%s get msg to cancel\n", Name)
			return
		default:
			fmt.Printf("%s is running \n", Name)
			time.Sleep(1 * time.Second)
		}
	}
}

func workWithValue(ctx context.Context, name String) {
	for {
		SELEct {
		case <-ctx.Done():
			fmt.Printf("%s get msg to cancel\n", Name)
			return
		default:
			value := ctx.Value("key").(String)
			fmt.Printf("%s is running value=%s \n", name, value)
			time.Sleep(1 * time.Second)
		}
	}
}
@H_801_3@这段代码中,都是一条链路下来的
根节点 context.BACkground() -> ctxa -> ctxb -> oc
其中ctxa加了个时间控制,所以到达一定的时间就会自动关闭
oc附带了个键对值

大佬总结

以上是大佬教程为你收集整理的Go基础知识梳理(四)全部内容,希望文章能够帮你解决Go基础知识梳理(四)所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: