goroutine原理
-
-
多个线程在多个核的cpu上运行,就是并行
协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现
线程:一个线程上可以跑多个协程,协程是轻量级的线程
import ( "fmt" "runtime" ) func main() { // 获取cpu个数 num := runtime.NumCPU() // 设置cpu运行的核数 runtime.GOMAXPROCS(num) fmt.Println(num) }
import ( "fmt" "sync" "time" ) var ( m = make(map[int]uint64) lock sync.Mutex ) type task struct { n int } func calc(t *task) { var sum uint64 sum = 1 for i := 1; i < t.n; i++ { sum *= uint64(i) } lock.Lock() m[t.n] = sum lock.Unlock() } func main() { for i := 0; i < 16; i++ { t := &task{n: i} go calc(t) } time.Sleep(10 * time.Second) lock.Lock() for k, v := range m { fmt.Printf("%d = %v\n", k, v) } lock.Unlock() }
-
-
先进先出
-
线程安全,多个goroutine同时访问,不需要加锁
-
channel是有类型的,一个整数的channel只能存放整数
var 变量 chan 类型 var test chan int var test chan string var test chan map[string]string var test chan stu var test chan *stu // channel声明后要用make初始化,否则会报错 var intChan chan int intChan = make(chan int, 10) intChan <- 10
// 从channel中读数据 var testChan chan int testChan = make(chan int, 10) testChan <- 10 var a int a = <- testChan
import ( "fmt" "time" ) func write(ch chan int) { for i := 0; i < 100; i++ { ch <- i } } func read(ch chan int) { for { var b int b = <- ch fmt.Println(b) } } func main() { intChan := make(chan int, 10) go write(intChan) go read(intChan) time.Sleep(10 * time.Second) }
func writing(ch chan int) { for i := 0; i < 100; i++ { ch <- i // 当i等于9后就不再打印了,channel被阻塞 fmt.Printf("channel %d\n", i) } } func main() { intChan := make(chan int, 10) // 只给10个空间 writing(intChan) }
那为什么在上一个例子中,channel没有出现阻塞的情况呢?原来是read方法在从chennel中取值,有进有出,就不会阻塞
b, ok := <- ch if ok == false { fmt.Println("channel空了") }
intChan := make(chan int, 10) for i := 0; i < 10; i++ { intChan <- i } close(intChan)
func main() { intChan := make(chan int, 10) // 给10个 for i := 0; i < 10; i++ { intChan <- i } close(intChan) // 必须关闭管道,下面遍历才不会阻塞,关闭后,下面遍历完channel后会自动退出for循环 for v := range intChan { fmt.Println(v) } }
var ch <- chan int // 只读 var ch chan <- int // 只写 // 一般应用在函数或者方法的形参上 fun test(ch <- chan int, exitChan chan <- int) {}
import ( "fmt" "time" ) func main() { var ch chan int ch = make(chan int, 10) for i := 0; i < 10; i++ { ch <- i } for { select { case v := <- ch: fmt.Println(v) default: fmt.Println("get data timeout") time.Sleep(time.Second) } } }
func test() { var m map[string]int m["stu"] = 10 } func main() { for i := 0; i < 100; i++ { go test() } time.Sleep(time.Second * 1000) }
上面的程序是有问题的,因为map没有初始化就直接赋值了,所以会抛出panic,程序停止,那如果不希望程序停止那就需要使用recover()捕获异常
func test() { // 在这里捕获异常 defer func() { if err := recover(); err != nil { fmt.Println(err) } }() var m map[string]int m["stu"] = 10 } func main() { for i := 0; i < 100; i++ { go test() } time.Sleep(time.Second * 1000) }