GO chan思绪整理(非缓冲chan)

初次学习go chan思路整理过程,当然也不免会碰到些低级错误
代码

package mainimport "fmt"func main() { ch := make(chan int) ch <- 20 ch <- 21 value := <-ch fmt.Printf("%s\n",value) value = https://www.it610.com/article/<-ch fmt.Printf("%s\n",value) }

运行结果
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]: main.main() /Users/arno/go/src/go_study/goroutine/channel/channel1.go:9 +0x59

解释 chan是协程之间的数据传输的通道,但是这里只有一个主协程(main函数),所以会出现上面的错误。
说到协程这里也简单说明一下:
协程比线程更轻量级。协程也是宿主在线程中,一个线程可以包含多个协程。协程是非抢占式的,协程的所有权是主动交出的,所以它在切换时只需要记录点,而不会像线程那样要快照很多数据。
解决思路 加个协程试试,看代码
package mainimport "fmt"var ch1 chan int func HelloChan(){ ch1 <- 20 ch1 <- 21 }func main() { ch1 = make(chan int) go HelloChan() value := <-ch1 fmt.Printf("%d\n",value) value = https://www.it610.com/article/<-ch1 fmt.Printf("%d\n",value) }

运行结果:
20 21

疑问:两个协程是怎么样配合的呢?
我稍改造代码试了一下,上代码:
package mainimport ( "fmt" "time" )var ch1 chan int func HelloChan(){ ch1 <- 20 fmt.Println("inner helloChan position 1") time.Sleep(time.Second*2) fmt.Println("间隔2秒后输出 :\n") fmt.Println("inner helloChan position 2") ch1 <- 21 fmt.Println("inner helloChan position 3") }func main() { ch1 = make(chan int) go HelloChan() value := <-ch1 fmt.Printf("%d\n",value) a:=0 a++ a++ fmt.Println("other code ",a) value = https://www.it610.com/article/<-ch1 fmt.Printf("%d\n",value) }

运行结果:
inner helloChan position 1 20 other code2 间隔2秒后输出 :inner helloChan position 2 inner helloChan position 3 21

根据结果分析运行流程:
GO chan思绪整理(非缓冲chan)
文章图片

总结: 通篇说明了两个关键点:
1、chan是两个协程间通讯的,否则会报错,所以要注意某协程会提前结束导致报错
2、当协程读取chan时一定要读取到的,否则会被阻塞在这里
3、当协程向chan写入数据时,要等待被其它线程读取,否则也会阻塞。(关于这点我未加在上面的代码中,但我自己是实验过的,为了示例的简洁性,没加那么多复杂的逻辑进来)
篇外: 当有chan的交互时协程被阻塞,但是没有chan交互时协程间是相互不受影响的,来看一下代码:
package main
import ( "fmt" "time" )func worker1(){ time.Sleep(time.Second*1) fmt.Println("worker1 :1 \n") time.Sleep(time.Second*1) fmt.Println("worker1 :2 \n") time.Sleep(time.Second*1) fmt.Println("worker1 :3 \n") time.Sleep(time.Second*1) fmt.Println("worker1 :4 \n") }func worker2(){ time.Sleep(time.Second*2) fmt.Println("worker2 :1 \n") time.Sleep(time.Second*2) fmt.Println("worker2 :2 \n") }func main() { go worker1() go worker2() time.Sleep(5*time.Second) }

【GO chan思绪整理(非缓冲chan)】运行结果:
worker1 :1 worker2 :1 worker1 :2 worker1 :3 worker2 :2 worker1 :4

    推荐阅读