go第三天

77 阅读2分钟

Go第三天--语言进阶

go 工程实践 语言进阶

goroutine Go语言可以充分发挥多核优势,高效运行。

  • 线程 消耗资源 线程跑多个协程,栈MB级别
  • 协程 轻量 轻量级现场,栈KB级别
func hello(i int) {
	println("hello goroutine:" + fmt.Sprint(i))
}
func hellogoroutine() {
	for i := 0; i < 5; i++ {
		go func(j int) {

			hello(j)
		}(i)
	}
	time.Sleep(time.Second)

}

func main() {
	hellogoroutine()
}

并行打印 乱序输出

//hello goroutine:4
//hello goroutine:3
//hello goroutine:2
//hello goroutine:1
//hello goroutine:0

Channel 通信

协程数据的传输推荐的是使用通道

例子

func CalSqueare() {
	src := make(chan int)
	dest := make(chan int, 3)
	go func() {
		defer close(src)
		for i := 0; i < 10; i++ {
			src <- i

		}
	}()
	go func() {
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}()
	for i := range dest {
		println(i)
	}

}

func main() {
	CalSqueare()
}

第一个线程负责生产数字发送到src 第二个线程遍历src里面的数字 主线程输出最后的平方数

Lock操作 用于解决线程安全

在 Go 语言中,可以使用 sync 包提供的锁机制来保护共享资源,避免出现竞争条件和数据竞争的情况。sync 包提供了多种锁机制,包括互斥锁(Mutex)、读写锁(RWMutex)、条件变量(Cond)等。

例子

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)
	println("没有锁", x)
	x = 0
	for i := 0; i < 5; i++ {
		go addwithlock()

	}
	time.Sleep(time.Second)
	println("有锁", x)
}

有锁输出正常的10000 没有锁可能会出现小于10000的值 教程演示了加锁和不加锁 不加锁会输出未知的结果

WaitGroup

WaitGroup 是 Go 语言标准库 sync 包中的一个结构体类型,用于等待一组协程或线程的执行完成。WaitGroup 维护了一个计数器,用于记录需要等待的协程或线程的数量,当计数器的值为 0 时,表示所有的协程或线程都已经执行完成,可以继续执行后续的操作。
WaitGroup 包含了三个方法:
1. Add(delta int):增加计数器的值,表示需要等待 delta 个协程或线程执行完成。
2. Done():减少计数器的值,表示一个协程或线程已经执行完成。
3. Wait():等待所有协程或线程执行完成,即计数器的值为 0。

使用 WaitGroup 可以方便地实现协程或线程之间的同步

例子

var wg sync.WaitGroup
func hello(i int) {
	println("hello goroutine:" + fmt.Sprint(i))
}
func hellogoroutine() {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(5)
		go func(j int) {
			defer wg.Done() //计时器

			hello(j)
		}(i)

	}
	wg.Wait() //用于阻塞
}

需要注意的是,在使用 WaitGroup 时,需要避免出现计数器值为负数的情况,否则会导致 panic 异常。因此,在增加计数器的值时,应该使用正整数;在减少计数器的值时,应该在协程或线程执行完成后调用 Done() 方法。