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

浙公网安备 33010602011771号