基础知识
进程和线程
- 进程
进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。 - 线程
线程是进程的一个执行实体,是CPU调度和分配的基本单位,它是比进程更小的能独立运行的基本单位。 - 协程
轻量级的线程
-联系
一个进程可以创建和撤销多个线程,同一个进程中的多个线程之间可以并发执行。
并发和并行
- 并发:多线程程序在一个核的CPU上运行
- 并行:多线程程序在多个核的CPU上运行
goroute
goroute调度模型
M:操作系统的线程
P:上下文
G:goroute、协程
-
关系:
一个P只能执行一个goroute,其余的在等待
-
goroute之间的通信:
1、全局变量和锁同步 2、channel
channel
- 初始化
var a chan int
a = make(chan int, 10)
- 读/写数据
// 写入管道
var b int
a <- b
// 读出管道
b = <- a
-
只读/写管道的定义
只读 var ch <-chan int 只写 var ch chan<- int
-
关闭channel
package main
import(
"fmt"
)
func testChan() {
var a chan int
a = make(chan int, 10)
for i := 0; i < 10; i++ {
a <- i
}
// 关闭管道
close(a)
for {
var b int
b,ok:=<-a
if ok== false{
fmt.Println("Chan Closed")
break
}
fmt.Println(b)
}
}
func main() {
testChan()
}
-
管道关闭例子
管道不关闭,forrnage会等待 管道关闭后,forrange退出 检测管道是否关闭 v,ok:=<-ch
package main
import (
"fmt"
)
func calc(taskChan chan int, resChan chan int,
exitChan chan bool) {
for v := range taskChan {
flag := true
for i := 2; i < v; i++ {
if v%i == 0 {
flag = false
break
}
}
if flag {
resChan <- v
}
}
fmt.Println("exit")
exitChan <- true
}
func main() {
intChan := make(chan int, 1000)
resultChan := make(chan int, 1000)
exitChan := make(chan bool, 8)
go func() {
for i := 0; i < 10000; i++ {
intChan <- i
}
close(intChan)
}()
for i := 0; i < 8; i++ {
go calc(intChan, resultChan, exitChan)
}
//等待所有计算的goroutine全部退出
go func() {
for i := 0; i < 8; i++ {
<-exitChan
fmt.Println("wait goroute ", i, " exited")
}
close(resultChan)
}()
for v := range resultChan {
fmt.Println(v)
}
}
-
channel同步例子
一个协程向管道写入,写完关闭管道,向标记管道丢一个东西 一个协程从管道读数据,读完也向标记管道丢一个东西 主线程从标记管道读东西,从而实现等待
package main
import (
"fmt"
)
func read(ch chan int, exitCh chan struct{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
var a struct{}
exitCh <- a
}
func write(ch chan int, exitCh chan struct{}) {
for {
a, ok := <-ch
if !ok {
break
}
fmt.Println(a)
}
var a struct{}
exitCh <- a
}
func main() {
ch := make(chan int, 10)
exitCH := make(chan struct{}, 2)
go read(ch, exitCH)
go write(ch, exitCH)
var total = 0
for _ = range exitCH {
total++
if total == 2 {
break
}
}
}
输出:
0
1
2
3
4
5
6
7
8
9
- select使用
package main
import (
"fmt"
"time"
)
func write(ch1 chan int, ch2 chan int) {
for i := 0; i < 10; i++ {
ch1 <- i
time.Sleep(time.Second)
ch2 <- i * 2
time.Sleep(time.Second)
}
}
func main() {
ch1 := make(chan int, 10)
ch2 := make(chan int, 10)
go write(ch1,ch2)
for {
select {
case v := <-ch1:
fmt.Println(v)
case v := <-ch2:
fmt.Println(v)
default:
fmt.Println("get data timeout")
time.Sleep(time.Second)
}
}
}
-
协程中的recover
防止协程中出现panic,导致主线程挂掉,对协程中的panic进行捕捉
package main
import (
"fmt"
"time"
)
func write() {
defer func() {
if err := recover(); err != nil {
fmt.Println("catch err")
}
}()
var m map[string]int
m["123"] = 1
}
func main() {
go write()
time.Sleep(time.Second)
}
输出:
catch err