协程(coroutine)是一种比线程更轻量级的并发执行单元,它的切换开销和内存栈的占用大小都比线程要小。只要内存足够,在一个线程中可有上万个或更多的协程。除了这些优点,对开发人员来说,在网络编程应用中,采用协程后的业务代码比那些采用异步或事件回调方式的代码更好维护。使用协程的业务逻辑代码表面看上去是同步执行的,编写这些代码时思维是连贯的,更符合人类的思维习惯;而采用异步和回调方式后,业务逻辑代码被分割(分拆)在多个回调方法中,开发人员的思维需要切换,是跳跃的,这样显然容易出错,并且一些场景下还要设计事件或会话上下文数据结构,来保存那些需要在多个回调方法间共享的状态数据。
Golang的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。
协程的执行线程
协程是在线程中执行的,在Golang中使用环境变量GOMAXPROCS来控制协程使用的线程数,它的缺省值是1,在1.5版本中改为cpu核数。也可在代码中调用
runtime.GOMAXPROCS(n int)函数来设置协程使用的线程数,例如
runtime.GOMAXPROCS(runtime.NumCPU()) 将协程使用的线程数设为cpu个数。
一个Golang进程启动后,该进程中的线程除了协程使用的GOMAXPROCS个线程外,通常还有其他额外的线程。当协程中的代码阻塞在一些系统调用中时,会产生或占用额外的线程,这些线程不算在(不包括)协程占用的GOMAXPROCS个线程中。Golang文档中关于GOMAXPROCS的描述如下:
The GOMAXPROCS variable limits the number of operating system threads that can execute user-level Go code simultaneously. There is no limit to the number of threads that can be blocked in system calls on behalf of Go code; those do not count against the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes the limit.
当协程阻塞在下列系统调用中时不会产生或占用额外的线程,此时阻塞的协程会被交换出去,协程调度器会调度执行其他可运行的协程。
- network input (socket io)
- sleeping
- channel operations
- blocking on primitives in the sync package.
其他的系统调用会产生额外的线程,例如disk io。如果很多协程同时读写磁盘文件会导致出现很多额外的线程。也就是Golang目前对network socket io会多路复用线程,对disk io不会复用线程。不过github上有个文件io包已经解决了该问题,使用该包读写文件不会出现过多线程。该包见https://github.com/npat-efault/poller,只适用于linux系统。
协程调度器
Golang 的调度器基本上是协作式,而不是抢占式,但也不是完全的协作式调度,在系统调用的函数入口处会有抢占。
例如对如下代码:
package main
import "fmt"
import "runtime"
import "time"
func cpuIntensive(p *int) {
for {
*p++
}
}
func other() {
...
}
func main() {
runtime.GOMAXPROCS(1)
x := 0
go cpuIntensive(&x)
time.Sleep(2* time.Millisecond)
go other()
time.Sleep(100000 * time.Second)
}
上面的代码中,cpuIntensive函数中有个无限循环,当执行go cpuIntensive(&x) 后,它会一直执行不被抢占,导致后面的other协程和main协程饿死,不会执行其中的代码,除非在无限循环中调用runtime.Gosched()让出cpu或加入系统调用函数。
上面的loop循环问题有望在Golang1.6中得到解决,也就是不再需要开发人员显式在代码中加入runtime.Gosched()。
另外当main函数退出时,Golang进程会直接退出,不会等待进程中未完成的协程。
参考文档:
- https://github.com/golang/go/issues/11462
- https://groups.google.com/forum/#!topic/golang-nuts/j51G7ieoKh4
相关推荐
一个基于golang实现的协程安全的mysql builder
第3章Go的协程rar 第4章示例环境搭建ram 第5章Go批里生成日志ar 第6章统计系统框架构成.rar 第7章统计统之口志费.rar 第8章统计系统之批星解析a 第9章统计系统之统计逻辑,rar 第10统计系统之存储器rar 第11章据可视...
讲述了golang的协程机制,是一篇论文,具体讲解了线程、调度器、协程的关系
通过go语言实现的通用协程池,带有使用案例。可以传递任意个数和任意类型的参数。
百度网盘资源,亲测可用,只是为了点积分,若侵权请告知立删
基于golang的动态协程池实现 功能 控制程序的协程数 动态修改程序的协程数 。。。 实例代码见example / main.go
基于Golang协程实现流量统计系统系列课程.txt
一个golang的任务协程池简单实现,用于限制系统无休止开辟协程执行任务的场景
基于Golang协程实现流量统计系统 最近刚出来的 我对这方面不感兴趣 只是拿出来分享 顺便挣点积分 谢谢大家 如果没有积分可以加群45.8.3(防删)74.310 群文件获取
主要介绍了golang协程池设计详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
golang协程机制很方便的解决了并发编程的问题,但是协程并不是没有开销的,所以也需要适当限制一下数量。这篇文章主要介绍了golang 40行代码实现通用协程池,需要的朋友可以参考下
start -> 2021年3月16日22:08:32use this project在config.json配置文件里根据json对应格式配置好账号密码后...123待完善 :获取分类所有ID时,天天酷跑分类怎样都获取不到细细回忆这个软件 竟没有一丝美好回忆end......
基于Golang协程实现流量统计系统 用到技术:Go基础知识,Go的协程,Nginx收集日志,Redis存储,PHP提供API,Ant Design做可视化输出 慕课网课程,分享百度网盘资源: : 更多Go语言实战课程推荐: Go实战仿百度云盘...
golang版本的RabbitMQ消息订阅的封装,可以多个生产者,多个消息订阅者,每个队列可以创建多个协程处理; 可能有些消费者需求需要分布式部署,那需要指定队列名,并且需要设置队列持久化,以及排他性QueueDeclare....
Golang 提供了database/sql包用于对SQL数据库的访问, 作为操作数据库的入口对象sql.DB, 主要为我们提供了两个重要的功能: •sql.DB 通过数据库驱动为我们提供管理底层数据库连接的打开和关闭操作. •sql.DB 为我们...
├─(10) 2-3 Golang协程基本示例.mp4 ├─(11) 3-1 Golang协程特性实践.mp4 ├─(12) 3-2 golang select多队列选择器.mp4 ├─(13) 3-3 selete等待机制.mp4 ├─(14) 4-1 快速构建一个示例网站(上).mp4 ├─(15) ...
进程、线程和协程 进程的定义: ...协程通过在线程中实现调度,避免了陷入内核级别的上下文切换造成的性能损失,进而突破了线程在IO上的性能瓶颈。 协程和线程的关系 协程是在语言层面实现对线程的调
基于epoll 协程池的golang网络库。支持epoll事件触发,读数据和业务逻辑处理分离,最大化利用cpu,防止内存急剧暴涨,适用于长连接、短连接,支持请求对象池和连接对象池
写了一个模拟程序对map中的一项进行读或者写,后台一直运行的协程阻塞的接受读写信号,并对map进行操作,但是读操作的时候没想好怎么返回这个值。 后来想到用传引用的方式,定义结构体,第一个参数是读写的标志,第...