我们从调度上声明线程与goroutine的区别
内存上
之前参考了几篇go语言中文社区的文章,发现人家的讲解已经很清晰了,所以这里我计划多一些我自己的理解(偏理论)的东西
go协程使用,需要用到的几种通讯方式有 sync,channel … (不下三种,水平有限,只会channel),go的官网文档介绍[sync:大部分都是适用于低水平程序线程,高水平的同步使用channel通信更好一些。],channel也是golang的最为核心的技术(论程序员的修养:channal是google的大佬底层封装的好)
阻塞/挂起线程类似于锁的概念或者说php/js中断点,只不过是可通过通讯方式来开启/关闭
声明方式
ch := make(chan int, 3)
运行方式’异步’, 仅限不阻塞情况下异步执行,阻塞后还是同步等待执行,第二个参数为缓冲的大小
使用
ch := make(chan int, 3)
ch <- 7
ch <- 8
ch <- 9
close(ch) // 关闭通道
for item := range ch{
fmt.Println(item)
}
// stystem out : 7 8 9 //遵循先进先出顺序
// 或者通过 人工 break 跳出循环
ch := make(chan int, 3)
ch <- 7
ch <- 8
ch <- 9
for item := range ch {
fmt.Println(item)
if len(ch) == 0 {
break // 人工跳出循环
}
}
声明方式
ch := make(chan int)
运行方式’同步’
使用情况
示例方法为省代码量,全用闭包代替(主要是一些死锁情况)
xChan := make(chan int)
xChan<-1
go func() {
// code ...
<-xChan
}()
fmt.Println("main done.. no deadlock")
// fatal error: all goroutines are asleep - deadlock!
xChan := make(chan int)
go func() {
// code ...
<-xChan
}()
xChan<-1
fmt.Println("main done.. no deadlock")
// main done.. no deadlock
c := make(chan int)
go func() {
c <- 1
}()
fmt.Println("main done.. no deadlock")
ch := make(chan int)
// 写入数据,堵塞当前线程, 没人取走数据阻塞不会释放
ch <- 1
//在此行执行之前Go就会报死锁
fmt.Println("main done.. no deadlock")
// 每个 case 必须是一个通信操作,要么是发送要么是接收。
// select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行(运行后终止)。一个默认的子句应该总是可运行的。
input := make(chan interface{})
// 另开一个线程添加chan数据
go func() {
for i := 0; i < 5; i++ {
input <- i
}
input <- "hello, world"
}()
//os.Exit(22)
// 主线程执行过快 没存进去 select 就开始取了
time.Sleep(2*time.Second)
select {
// 3个case随机执行'一次',没有可执行的便执行defaule
case msg1:=<-input:
fmt.Println(msg1,"---1")
case msg2:=<-input:
fmt.Println(msg2,"---2")
case msg3:=<-input:
fmt.Println(msg3,"---3")
default:
fmt.Println("close")
}