【Go】协程

今天主要学习了一下go语言的多线程,也写了一些例子,最开始还是很困惑。

比如下面这个例子:

package main

import "fmt"

func loop() {
	for i := 0; i < 10; i++ {
		fmt.Printf("%d\n", i)
	}
}

func main() {
	go loop()
}
都说go语言的多线程语法简单,只需要go+一个函数名称就可以,可是我执行上述代码以后却没有任何输出。很郁闷。

然后就查了很多关于go语言多线程的知识。

重点比如这篇:http://www.cnblogs.com/foxmailed/p/3509359.html

go的多线程准确是协程,goroutine。协程是比线程更轻量级的概念。这个具体体现在线程一般是内核支持的,需要系统调用和时钟中断来支持,吃内存费时间。所以,一个程序中如果有大量的线程,那么系统很可能吃不消。而协程则是运行在用户态的,具体是运行在某一个线程中,协程由用户态的调度器完成调度。所以相比较于java中的线程,每一次启动都需要切换到内核态,而且线程本身需要吃掉比较多的资源,协程就不需要切换内核态,而且需要的资源也很少,基本上只有2KB左右。这估计是go适合服务端开发的原因。

实际上,go内部有一个runtime层,里面实现了线程,协程以及调度等模块。go+func的语言用于开始一个协程或者goroutine,goroutine所对应的数据结构会保存其运行时的各种状态比如堆栈等动态信息。然后会有一个goroutine的队列,存放提交的goroutine。runtime的调度器会周期性地从队列中取gorouitne来执行。有一个类似线程池的东西会来执行每一个goroutine,如果有闲置的线程就会唤醒这个线程,否则如果全部的线程都在工作,就开始一个新的线程。runtime中有一个线程会监事每一个goroutine或者线程的执行,如果线程阻塞了,那么该线程就会被挂起,直到其他的goroutine唤醒它,如果一个goroutine的线程运行的太久,那么该线程会被剥夺来运行其他的goroutine。调度是抢占式的。所以创建协程的代价很低,而且可以用之前的线程来跑,效率比纯线程好。

具体过程在这本书里面很详细:

https://github.com/qyuhen/book/blob/master/Go%20学习笔记%20第四版.pdf

明白了go语言协程的大致模型,在最开始运行的时候,至少有两个goroutine一个是main的,一个是idle的,main的goroutine是主goroutine,只要主goroutine结束了,那么其他由main产生的goroutine也会被迫停止运行。

上面的例子就很好理解了。因为在一个函数中使用go开启一个协程以后,该函数是不会做任何等待的,而是直接执行本函数的下一条语句,所以这时main函数执行go loop()以后,直接向下执行,最后main函数直接就返回了,主协程结束,其他协程也结束,没有给loop协程运行的机会。

那么这里如果要等loop运行该怎么办?

一是可以在main的最后通过time的sleep函数等一下。二是通过channel机制,在main的最后调用一个read来读取loop写入的一个值,那么只要loop没有写入,main就会read阻塞在那知道loop写入。


package main

import "fmt"

var ch chan int = make(chan int)

func read() {
	fmt.Printf("%d", <-ch)

}

func write() {
	ch <- 1
}

func main() {
	go read()
	write()
}
但是以上这段代码也没有输出。channel只有两个操作,那么写入要么读取,这两个都是阻塞的,或者成对的,只要缺一个,另外一个都会阻塞。所以,才有了最开始使用main函数最后放一个read的方式来实现类似join的操作。

但是上面这个例子只是颠倒了read和write的顺序,我觉得也应该有输出才对。仔细想了一下,原因应该是,延迟问题。write执行以后,会等read函数来读取,否则write不会返回,当read的协程执行了读取操作以后,此时write就返回了,main就结束了,但是fmt还没有把channel里的数据打印出来,也就是延迟。所以main里面先写read肯定是没问题的,因为肯定是先写后读。

这个例子只要在main后面加一个sleep就会有输出了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值