Golang 并发Groutine实例解读(一)
Go语言的并发和并行
不知道你有没有注意到一个现象,还是这段代码,如果我跑在两个goroutines里面的话:
var quit chan int = make(chan int) func loop() {
for i := ; i < ; i++ {
fmt.Printf("%d ", i)
}
quit <-
} func main() {
// 开两个goroutine跑函数loop, loop函数负责打印10个数
go loop()
go loop() for i := ; i < ; i++ {
<- quit
}
}
我们观察下输出:
这是不是有什么问题??
以前我们用线程去做类似任务的时候,系统的线程会抢占式地输出, 表现出来的是乱序地输出。而goroutine为什么是这样输出的呢?
goroutine是在并行吗?
我们找个例子测试下:
package main import "fmt"
import "time" var quit chan int func foo(id int) {
fmt.Println(id)
time.Sleep(time.Second) // 停顿一秒
quit <- // 发消息:我执行完啦!
} func main() {
count :=
quit = make(chan int, count) // 缓冲1000个数据 for i := ; i < count; i++ { //开1000个goroutine
go foo(i)
} for i := ; i < count; i++ { // 等待所有完成消息发送完毕。
<- quit
}
}
让我们跑一下这个程序(之所以先编译再运行,是为了让程序跑的尽量快,测试结果更好):
go build test.go
time ./test
./test .01s user .01s system % cpu 1.016 total
我们看到,总计用时接近一秒。 貌似并行了!
我们需要首先考虑下什么是并发, 什么是并行
并行和并发
从概念上讲,并发和并行是不同的, 简单来说看这个图片
- 两个队列,一个Coffee机器,那是并发
- 两个队列,两个Coffee机器,那是并行
那么回到一开始的疑问上,从上面的两个例子执行后的表现来看,多个goroutine跑loop函数会挨个goroutine去进行,而sleep则是一起执行的。
这是为什么?
默认地, Go所有的goroutines只能在一个线程里跑 。
也就是说, 以上两个代码都不是并行的,但是都是是并发的。
如果当前goroutine不发生阻塞,它是不会让出CPU给其他goroutine的, 所以例子一中的输出会是一个一个goroutine进行的,而sleep函数则阻塞掉了 当前goroutine, 当前goroutine主动让其他goroutine执行, 所以形成了逻辑上的并行, 也就是并发。
真正的并行
为了达到真正的并行,我们需要告诉Go我们允许同时最多使用多个核。
回到起初的例子,我们设置最大开2个原生线程, 我们需要用到runtime包(runtime包是goroutine的调度器):
import (
"fmt"
"runtime"
) var quit chan int = make(chan int) func loop() {
for i := ; i < ; i++ { //为了观察,跑多些
fmt.Printf("%d ", i)
}
quit <-
} func main() {
runtime.GOMAXPROCS() // 最多使用2个核 go loop()
go loop() for i := ; i < ; i++ {
<- quit
}
}
这下会看到两个goroutine会抢占式地输出数据了。
我们还可以这样显式地让出CPU时间:
func loop() {
for i := ; i < ; i++ {
runtime.Gosched() // 显式地让出CPU时间给其他goroutine
fmt.Printf("%d ", i)
}
quit <-
} func main() { go loop()
go loop() for i := ; i < ; i++ {
<- quit
}
}
观察下结果会看到这样有规律的输出:
其实,这种主动让出CPU时间的方式仍然是在单核里跑。但手工地切换goroutine导致了看上去的“并行”。
runtime调度器
runtime调度器是个很神奇的东西,但是我真是但愿它不存在,我希望显式调度能更为自然些,多核处理默认开启。
关于runtime包几个函数:
Gosched
让出cpuNumCPU
返回当前系统的CPU核数量GOMAXPROCS
设置最大的可同时使用的CPU核数Goexit
退出当前goroutine(但是defer语句会照常执行)
总结
我们从例子中可以看到,默认的, 所有goroutine会在一个原生线程里跑,也就是只使用了一个CPU核。
在同一个原生线程里,如果当前goroutine不发生阻塞,它是不会让出CPU时间给其他同线程的goroutines的,这是Go运行时对goroutine的调度,我们也可以使用runtime包来手工调度。
本文开头的两个例子都是限制在单核CPU里执行的,所有的goroutines跑在一个线程里面,分析如下:
- 对于代码例子一(loop函数的那个),每个goroutine没有发生堵塞(直到quit流入数据), 所以在quit之前每个goroutine不会主动让出CPU,也就发生了串行打印
- 对于代码例子二(time的那个),每个goroutine在sleep被调用的时候会阻塞,让出CPU, 所以例子二并发执行。
Golang 并发Groutine实例解读(一)的更多相关文章
- Golang 并发Groutine实例解读(二)
go提供了sync包和channel机制来解决协程间的同步与通信. 一.sync.WaitGroup sync包中的WaitGroup实现了一个类似任务队列的结构,你可以向队列中加入任务,任务完成后就 ...
- Golang 并发Groutine详解
概述 1.并行和并发 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行. 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在 ...
- 【WCF--初入江湖】08 并发与实例模式
08 并发与实例模式 1. 实例上下文模式 一个服务代理:servicePoxy ChannelFactory<IService1> factoryservicel = new Cha ...
- golang并发编程
golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...
- 马蜂窝搜索基于 Golang 并发代理的一次架构升级
搜索业务是马蜂窝流量分发的重要入口.很多用户在使用马蜂窝时,都会有目的性地主动搜索与自己旅行需求相关的各种信息,衣食住行,事无巨细,从而做出最符合需求的旅行决策. 因此在马蜂窝,搜索业务交互的下游模块 ...
- Golang 并发简介
并发概要 随着多核CPU的普及, 为了更快的处理任务, 出现了各种并发编程的模型, 主要有以下几种: 模型名称 优点 缺点 多进程 简单, 隔离性好, 进程间几乎无影响 开销最大 多线程 目前使用最多 ...
- golang 并发顺序输出数字
参考 package main import ( "fmt" "sync/atomic" "time" ) func main() { va ...
- Python并发编程实例教程
有关Python中的并发编程实例,主要是对Threading模块的应用,文中自定义了一个Threading类库. 一.简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态 ...
- Golang并发原理及GPM调度策略(一)
其实从一开始了解到go的goroutine概念就应该想到,其实go应该就是在内核级线程的基础上做了一层逻辑上的虚拟线程(用户级线程)+ 线程调度系统,如此分析以后,goroutine也就不再那么神秘了 ...
随机推荐
- .Net Core in Docker - 在容器内编译发布并运行
Docker可以说是现在微服务,DevOps的基础,咱们.Net Core自然也得上Docker..Net Core发布到Docker容器的教程网上也有不少,但是今天还是想来写一写. 你搜.Net c ...
- vs installer 将.net framework 集成到安装包中
Missing .NET Framework 4.0 in Visual Studio 2017 Prerequisites whenhttps://stackoverflow.com/questio ...
- 用MVC5+EF6+WebApi 做一个考试功能(五) 前端主题
内容概述 前面絮絮叨叨没正事,到现在为止也没有开始写代码,不过在考虑下貌似这一节还是开始不了. B/S架构开发有一个特点,就是用浏览器打开,不同的用户群体可能有不同的风格,不论是管理平台还是普通的网站 ...
- day 81 天 ORM 操作复习总结
# ###############基于对象查询(子查询)############## 一.对多查询 正向查询 from django.shortcuts import render,HttpResp ...
- 《JAVA与模式》之桥梁模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述桥梁(Bridge)模式的: 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式. ...
- 【wepy实战】wepy搭建完整项目
使用小程序框架wepy,搭建完整实战项目.文章将从项目结构.配置.模块等进行逐步分析和学习. 文章适合小程序开发新手以及有经验的小程序developer,不喜勿喷,不吝赐教! 本文为作者原创,转发请标 ...
- CSS中的BFC详解
引言: 这篇文章是我对BFC的理解及总结,带你揭开BFC的面纱.你将会知道BFC是什么,形成BFC的条件,BFC的相关特性,以及他的实际应用. 一.何为BFC BFC(Block Formatting ...
- 【NOIP2017】 宝藏 状压dp
为啥我去年这么菜啊..... 我现在想了$20min$后打了$10min$就过了$qwq$. 我们用$f[i][j]$表示当前深度为$i$,访问了状态$j$中的所有点的最小代价. 显然$f[i][j] ...
- javascript数据结构与算法--基本排序算法(冒泡、选择、排序)及效率比较
javascript数据结构与算法--基本排序算法(冒泡.选择.排序)及效率比较 一.数组测试平台. javascript数据结构与算法--基本排序(封装基本数组的操作),封装常规数组操作的函数,比如 ...
- SAS->关联分析实践
SAS系统被誉为国际上的标准软件系统,本文将详细介绍如何在SAS/EM模块中进行关联规则数据挖掘,使用的软件版本是SAS 9.1.3下的Enterprise Miner 4.3: 从SAS顶端的[解决 ...