这是我参与「第五届青训营 」笔记创作活动的第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可以通过以下的方式创建单元测试:
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*?
}