go语言进阶与依赖管理

go语言进阶与依赖管理

  • 1.语言进阶(并发编程)
    • 1.0 并发与并行
    • 1.1 协程-go routine
    • 1.2 缓冲区-channel
    • 1.3 sync
      • 1.3.1 锁-lock
      • 1.3.2 waitgroup
  • 2 依赖管理
    • 2.1 演变
    • 2.2 三要素

1.语言进阶(并发编程)

1.0 并发与并行

并发:多线程程序在单核cpu运行(主要是调度)
并行:多线程程序在多核cpu运行
go语言为并发而生。

1.1 协程-go routine

实现高并发
协程-用户态,轻量级,栈MB级别
线程-内核态,线程跑多个协程,栈KB级别

package main

import (
	"fmt"
	"time"
)

func hello(i int) {
	println("hello goroutine :" + fmt.Sprint(i))
}
func main() {
	for i := 0; i < 5; i++ {
		go func(j int) { //匿名函数
			hello(j)
		}(i)
	}
	time.Sleep(time.Second) //保证子协程运行完之前主协程不退出
}

1.2 缓冲区-channel

通过通信共享内存

// 这个程序就是创建了两个channel,一个是src,一个是dest,src写入0-9的数字,dest读取src中的数字并将它的平方写入dest中,最后遍历dest并输出。
package main

import "fmt"

func CalSquare() {
	src := make(chan int)     //src无缓冲队列
	dest := make(chan int, 3) //dest有缓冲队列(3)
	//缓冲区大小实际上是在控制 channel 在没有接收者读取数据时能够存储多少个元素。
	//当缓冲区大小为3时,这个channel可以存储3个元素,当缓冲区已经有3个元素时,如果还有新的数据需要写入channel,
	//那么会阻塞直到缓冲区有空闲位置,所以这里的缓冲区并不会影响结果的输出。
	go func() {
		defer close(src) //在当前函数func()执行完毕之后关闭 src channel。关闭后,就不能再向它写入数据,但是可以从它读取数据。

		for i := 0; i < 10; i++ {
			src <- i //意思是将 i 写入 src channel。这里的 i 是一个循环变量,在循环体中每次迭代时都会被赋值。所以这个循环体中的语句就是不断地将 0~9 的数字写入 src channel。
		}
	}()

	go func() {
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}() //该处缓冲为3是为了不让下方的消费者的消费速度影响生产速度

	for i := range dest {
		//复杂操作
		fmt.Println(i)
	}

}

func main() {
	CalSquare()
}

1.3 sync

sync包下的关键字,有lock、waitgroup,主要实现并发安全操作和协程的同步

1.3.1 锁-lock

// 通过共享内存实现通信(不推荐)-并发安全性的考虑
package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	x    int64
	lock sync.Mutex
)

// 对比加锁和不加锁的两种输出
func addWithLock() {
	for i := 0; i < 2000; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}

func addWithoutLock() {
	for i := 0; i < 2000; i++ {
		x += 1
	}
}

func Add() {
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	time.Sleep(time.Second) //暂停一秒钟
	fmt.Println("WithoutLock:", x)

	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	time.Sleep(time.Second) //暂停一秒钟
	fmt.Println("WithLock:", x)

}

func main() {
	Add()
}

1.3.2 waitgroup

// waitgroup也在sync下,有Add\Wait\Done.维护一个计时器,可以增加和减少
package main

import (
	"fmt"
	"sync"
)

func hello(i int) {
	println("hello goroutine :" + fmt.Sprint(i))
}
func main() {
	//使得27goroutine里的Sleep变得优雅
	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func(j int) { //匿名函数
			defer wg.Done()
			hello(j)
		}(i)
	}
	wg.Wait()
}

2 依赖管理

2.1 演变

GOPATH->升级为Go vendor->升级为Go Module

2.2 三要素

  1. go.mod配置文件,描述依赖(依赖管理基本单元-原生库-单元依赖)
module xxx(从哪里找到这个模块 如github仓库。每个package下都要有。)
go 1.16 (原生库)
require(
	module_path  版本号(有语义化版本和基于commit伪版本两种)
	...(可以有直接依赖、间接依赖、incompatible不兼容代码)
)
  1. Proxy为中心仓库管理依赖库
    Proxy是一个服务站点。为了解决第三方代码托管平台对于版本更新的一系列问题,Proxy会缓存软件内容,保证依赖的稳定性和可靠性。以后就可以从Proxy拉取依赖。
    GOPROXY="https://proxy1.cn,https://proxy2.cn,direct"则会按照proxy1->proxy2->direct(第三方源站)的顺序去寻找依赖
  2. go get/mod为本地工具
    go get example.org/pkg
    @update(默认)
    @none(删除依赖)
    @v1.1.2(tag语义版本)
    @23dfdd5(特定的commit)
    @master(分支的最新commit)
    go mod
    init(初始化,创建go.mod文件)
    download(下载模块到本地缓存)
    tidy(增加需要的依赖,删除不需要的依赖)

你可能感兴趣的:(Go语言,golang,开发语言)