首页 > 其他分享 >【Go】协程

【Go】协程

时间:2022-11-11 12:32:03浏览次数:73  
标签:协程 read goroutine go 线程 Go main


今天主要学习了一下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语言多线程的知识。

重点比如这篇:​​javascript:void(0)​​

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就会有输出了。


标签:协程,read,goroutine,go,线程,Go,main
From: https://blog.51cto.com/u_15873544/5844600

相关文章

  • Django APIView
    defget(self,request):print("================用户行为列表")dictionary_key=self.request.query_params.get('data_point_app_id')print('---------445-......
  • MixGo Max主控板使用Mixly最新版软件识别不到串口解决方法
    首先安装创客驱动文件,全部选择安装即可,安装之前请将杀毒软件关闭!创客驱动文件下载出现安装失败的驱动,说明已经安装过对应的驱动,点击确定即可。驱动安装完成后,......
  • django template 例子
    template不是django中的内容,而是在python中的。只是在django的松偶合的思想正好用到了这个东西。即写好界面的模板,然后再写好业务逻辑,最后组合即可,这样就将界面与逻辑分开来......
  • 【MongoDB】shard切分 原理
    1.角色:在一个MongoDB的shard集群中,会有三种角色:shard,config和routingshard:每一个shard节点都会包含数据集的一部分,是存储真正数据的节点;config:主要存储元数据或者配置信息,比......
  • django 配置静态文件
    在django中使用图片、css、或者js文件时,并不能直接使用,而要进行配置,也就是所谓的静态文件配置。1配置settings.py文件:STATIC_ROOT变量设置为空,不知道这个有什么用STATIC_URL......
  • Go实现栈与队列基本操作
    @目录一前言二实现栈与队列基本操作2.1栈基本操作2.2队列基本操作三用栈实现队列3.1理论3.2算法题3.3思路3.4代码部分四用队列实现栈4.1理论4.2算法题4.3思路......
  • django 命令行方式使用model建数据库
    提前建立好项目根目录mysite,cd到mysite里面,使用如下命令创建一个名为FirstSql的项目:pythondjango-admin.pystartprojectFirstSql再cd到FirstSql下面,构建一个app,这个app......
  • django+命令行 Helloworld程序
    这里说一下如何使用命令行的方式来构建一个Helloworld项目。当然,python和django一定要先安装。这个在另一篇中有提到,就不细细说了。一切安装完毕之后,就可以新建工程了,选择一......
  • django+uwsgi+nginx+docker 部署出现的问题汇总
    前言部署环境,虚拟机ubuntu20.04,docker+uwsig+django+nginx部署,django+uwsgi一个容器,nginx一个容器。测试出现问题总结:1.postmane发送请求时,postman显示Error:socket......
  • 深度解密Go语言之sync.map
    工作中,经常会碰到并发读写map而造成panic的情况,为什么在并发读写的时候,会panic呢?因为在并发读写的情况下,map里的数据会被写乱,之后就是 Garbagein,garbageout,还......