golang 线程与通道
fmt.Println("2") time.Sleep(1 * time.Second) } 我只是在最后加了一行让主线程休眠一秒的代码,程序就会依次打印出2、3、1。 那为什么会这样呢?因为程序会优先执行主线程,主线程执行完成后,程序会立即退出,没有多余的时间去执行子线程。如果在程序的最后让主线程休眠1秒钟,那程序就会有足够的时间去执行子线程。 线程先讲到这里,下面我们来看看通道吧。 通道又叫channel,顾名思义,channel的作用就是在多线程之间传递数据的。 创建无缓冲channel chreadandwrite:=make(chanint) chonlyread := make(<-chan int) //创建只读channel chonlywrite := make(chan<- int) //创建只写channel 下面我们来看一个例子: ch:=make(chanint) ch <- 1 go func(){ <-ch fmt.Println("1") }() fmt"2") 这段代码执行时会出现一个错误:fatal error: all goroutines are asleep - deadlock! 这个错误的意思是说线程陷入了死锁,程序无法继续往下执行。那么造成这种错误的原因是什么呢? 我们创建了一个无缓冲的channel,然后给这个channel赋值了,程序就是在赋值完成后陷入了死锁。因为我们的channel是无缓冲的,即同步的,赋值完成后来不及读取channel,程序就已经阻塞了。这里介绍一个非常重要的概念:channel的机制是先进先出,如果你给channel赋值了,那么必须要读取它的值,不然就会造成阻塞,当然这个只对无缓冲的channel有效。对于有缓冲的channel,发送方会一直阻塞直到数据被拷贝到缓冲区;如果缓冲区已满,则发送方只能在接收方取走数据后才能从阻塞状态恢复。 对于上面的例子有两种解决方案: 1、给channel增加缓冲区,然后在程序的最后让主线程休眠一秒,代码如下: ch:=make(chanint,1) chgov:=<-ch fmt.Println(vtime.Sleep(* time.Second"2") 这样的话程序就会依次打印出1、2 2、把ch<-1这一行代码放到子线程代码的后面,代码如下: ch:=make(chanint) ) 这里就不用让主线程休眠了,因为channel在主线程中被赋值后,主线程就会阻塞,直到channel的值在子线程中被取出。 最后我们看一个生产者和消费者的例子: import"time" ) funcproduce(pchan int)for i0;<10 i++p i "send:",} consumer(c<-chan<-c "receive:" vmain()make( produce(ch consumer} 在这段代码中,因为channel是没有缓冲的,所以当生产者给channel赋值后,生产者这个线程会阻塞,直到消费者线程将channel中的数据取出。消费者第一次将数据取出后,进行下一次循环时,消费者的线程也会阻塞,因为生产者还没有将数据存入,这时程序会去执行生产者的线程。程序就这样在消费者和生产者两个线程间不断切换,直到循环结束。 下面我们再看一个带缓冲的例子: } 在这个程序中,缓冲区可以存储10个int类型的整数,在执行生产者线程的时候,线程就不会阻塞,一次性将10个整数存入channel,在读取的时候,也是一次性读取。 本文来自:CSDN博客 感谢作者:niechaoya 查看原文:golang 线程与通道 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |