go语言进阶与依赖管理 | 青训营

77 阅读1分钟

进阶

goroutine 和 channel 实例

A 线程协程 0~9 个数字

B 线程协程 计算 接受到的数字 的平方

主函数输出 B 协程计算的

package main

import (
    "fmt"
)

func main() {
    src := make(chan int)      // 无缓冲通道
    dest := make(chan int, 10) // 有缓冲通道
    go func() { // A
        defer close(src)
        for i := 1; i <= 10; i++ {
            src <- i
        }
    }()

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

    for i := range dest {
        fmt.Println(i)
    }
}
  • 无缓冲通道 发送方和接收方,必须同时发送和接受,也就是同步

  • 有缓冲通道 发送方可以先将东西放到通道,接收方需要了就从通道拿

lock 并发安全

package main

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

var (
	x    int64
	lock sync.Mutex
)

func addWithlock() {
	for i := 0; i < 2e3; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}

func addWithoutlock() {
	for i := 0; i < 2e3; i++ {
		x += 1
	}
}

func main() {

	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutlock() // 无锁加法
	}
	time.Sleep(time.Second)
	fmt.Println("无锁:", x)

	x = 0
	for i := 0; i < 5; i++ {
		go addWithlock() // 有锁加法
	}
	time.Sleep(time.Second)
	fmt.Println("有锁:", x)
}

输出:

无锁:9767
有锁:10000

在不加锁的情况下,x 被5个协程同时访问,某些+1加在了错误的 x 上面 因此,共享内存需要特别注意并发安全

WaitGroup 协程计数器

创建一个协程计数器 var wg sync.WaitGroup 协程数量增加 1 个 wg.Add(1) 协程数量减少 1 个 wg.Done() 等待协程数量归零 wg.Wait()

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func hello(i int) {
	defer wg.Done() // 当函数结束,代表一个协程结束
	fmt.Println(i)
}

func main() {
	for i := 0; i < 5; i++ {
		wg.Add(1)
        go hello(i)
	}
	wg.Wait() // 等待协程全部结束
}

依赖管理