1. 对并发和并行的一点小认知
只有多核才有并行。
2. goroutine哲学:
通过通信去共享内存,而不是通过共享内存去通信
这也是go语言和其它语言最大的不同点。
3. main函数执行启动本质上就是启动了一个goroutine
4. 主协程和非主协程
主协程退出后,默认其它的非主协程都会退出;这就像一个boss,死掉后;它的小鬼自动消失;
5. sync.WaitGroup
保证所有协助都执行完再退出。
默认情况下,主协助执行完后,如果直接退出,那么其它次协程都会消失;那么也就不能正常执行完。
为了保证所有协程(goroutine)都能正常执行,我们可以通过sync包来保证所有协程都能正常执行。
- 在开启一个goruntine前先添加
w.Add()
- 在gorountine开启的函数内,defer添加
w.Done()
保证释放 - 主协程中添加
w.Wait()
等待所有协程能执行完
看代码:
package main
import (
"fmt"
"sync"
"time"
)
// 等效于 var w = sync.WaitGroup{} 推荐按照这个写法
var w sync.WaitGroup
func main() {
// 迭代字母 注意这里是字符 unicode字符属于rune = int32
for i := 'A'; i <= 'E'; i++ {
w.Add(1) // 在开启goroutine前,每增加一个gorotinue 调用一次Add
go PrintLetters(i)
}
w.Wait() // 等待所有goroutine执行完
}
func PrintLetters(ch rune) {
defer w.Done() // 每次运行完goroutine 标记一下
fmt.Printf("%c\n", ch) // 用c代替字符
time.Sleep(time.Second) // 模拟耗费时
}
我们改成goroutine后发现程序执行总时间缩短了,因为并发执行。
上面的代码的知识点有点多;下面列出来一一说明:
6. var a xx结构体
-
var a Person
这种写法,基本上和var a = Person{}
等价 - 推荐
var a = Person{}
显示初始化 -
var a Person
之所有效,机理在于go的变量定义会给默认值,比如整数的默认值就是0
7. 字符的类型为rune = int32
- 因为是整数,所以可以执行加法
// 迭代字母 注意这里是字符 unicode字符属于rune = int32
for i := 'A'; i <= 'E'; i++ {
//xxx
}
- 打印字符通过
%c
fmt.Printf("%c\n", ch)
8. runtime包runtime.NumCPU()
查看机器核心数
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println(runtime.NumCPU())
}
9. runtime.GOMAXPROCS()
GOMAXPROCS用于设置程序运行并行线程数,一般和物理机核心数保持一致就行;从1.5版本开始后,它的默认值就是物理机器核心;不需要手动设置,也不推荐。
10 .runtime.Gosched
让出当前gorountinue的执行
它会让出当前gorountine的执行,让其它gorountine执行, 当前gorountine也会执行;只是执行交给了go调度器。
它有点像一种谦让行为,本该自己执行,却让出,让其它代码先执行;
这是一种go提供的干预gorountine调度的方式。
10. runtime.Goexit
- 退出当前gorountine
- 退出前defere会正常执行的(放心)
网友评论