Go进阶|青训营笔记

85 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第2天。

课堂主要内容

  • 并发编程
  • 单元测试

并发编程

并发

多线程程序在一个核的cpu上运行

并行

多线程程序在多个核的cpu上运行

协程(Goroutine):

线程:内核态,轻量级进程,栈MB级别。在进行创建、切换、停止时都会由操作系统本身来完成操作。

协程:用户态,线程跑多个协程,栈KB级别。在进行创建、切换、停止时都会由go语言本身来完成操作

在go中可以快速启动一个协程:

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)
}

channel(消息队列):

在channel未满或未空之前,向通道发送或接受并不会导致阻塞。

对于无缓冲channel来说因为缓冲为空,所以发送和接受操作会直接阻塞,直到有其他协程来接受和发送。

package concurrence

func CalSquare() {
	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)
	}
}

waitGroup:

有很多时候我们需要等待另一个线程的运行结果,对于这种情况可以用上面等待和无缓冲channel的方式解决。 但是当处理的线程数量多了上面的方式就会很麻烦。

可以使用sync.WaitGroup来等待多个协程退出。

func hello(i int) {
	println("hello world : " + fmt.Sprint(i))
}

func ManyGo() {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(j int) {
			defer wg.Done()
			hello(j)
		}(i)
	}
	wg.Wait()
}

单元测试

go可以通过以下的方式创建单元测试:

测试文件.png

array.go:

func AppendInt() {
	intArray := [3]int64{1, 2, 3}
	func(arr [3]int64) {
		arr[2] = 4
		fmt.Println("inner func array:",arr)
	}(intArray)

	fmt.Println("outer func array:",intArray)
}

array_test.go:

func TestAppendInt(t *testing.T) {
	AppendInt()
}

mock

在程序中难免会出现一些需要外部依赖数据的函数,要测试这种函数我们需要保证依赖数据的每一次测试都是相同的。这时候就要请出mock, 为一个函数打桩在该函数执行的时候会自动把函数地址替换。

package main

import (
	"fmt"
	"os"
	"strings"

	"bou.ke/monkey"
)

func main() {
	monkey.Patch(fmt.Println, func(a ...interface{}) (n int, err error) {
		s := make([]interface{}, len(a))
		for i, v := range a {
			s[i] = strings.Replace(fmt.Sprint(v), "hell", "*bleep*", -1)
		}
		return fmt.Fprintln(os.Stdout, s...)
	})
	fmt.Println("what the hell?") // what the *bleep*?
}