Go语言_并发篇
当被问到为什么用Go语言,一定不得不提的是Go语言的并发程序编写。在C语言中编写非常繁琐复杂的并发程序在Go语言中总是显得如此便捷。
Go中并发程序依靠的是两个:goroutine和channel
理解什么是goroutine?
对于初学者,goroutine直接理解成为线程就可以了。当对一个函数调用go,启动一个goroutine的时候,就相当于起来一个线程,执行这个函数。
实际上,一个goroutine并不相当于一个线程,goroutine的出现正是为了替代原来的线程概念成为最小的调度单位。一旦运行goroutine时,先去当先线程查找,如果线程阻塞了,则被分配到空闲的线程,如果没有空闲的线程,那么就会新建一个线程。注意的是,当goroutine执行完毕后,线程不会回收推出,而是成为了空闲的线程。
关于goroutine的理解,推荐看这个帖子:http://groups.google.com/group/golang-china/browse_thread/thread/0e9d683ca766ec00
goroutine的使用
使用非常简单,在函数前增加一个go
f(11)
go f(11) //这个是让f()函数作为goroutine运行
但是go有一个缺点,主线程要等待一个goroutine结束再处理怎么办?拿《学习go语言》中的一个例子说明。
这里的第18行为什么要sleep? 这里是为了等上面两个go ready处理完成。
好了,这里就出来了一个需求:一个goroutine结束后必须要向主线程传输数据,告诉主线程这个goroutine已经结束了。
这里就引进了channel的概念
channel的使用
channel的意思用白话可以这么理解:主线程告诉大家你开goroutine可以,但是我在我的主线程开了一个管道,你做完了你要做的事情之后,往管道里面塞个东西告诉我你已经完成了。
上面的例子就可以改为:
从这个程序得到的几点信息:
1 channel只能使用make来进行创建
基本格式是 c := make(chan int)
int是说明这个管道能传输什么类型的数据
2 往channel中插入数据的操作
c <- 1
是不是很形象
3 从channel中输出数据
<- c
4 为什么需要输出两次(4和5两行?)
因为2和3启动了两个goroutine,每个goroutine都往管道输出一个1,因此主线程要接收两次才能说明两个goroutine都结束了
channel的进一步理解:
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/
http://blog.dccmx.com/2012/03/small-problem-about-goroutine/
channel分为两种:一种是有buffer的,一种是没有buffer的,默认是没有buffer的
ci := make(chan int) //无buffer
cj := make(chan int, 0) //无buffer
cs := make(chan int, 100) //有buffer
有缓冲的channel,因此要注意“放”先于“取”
无缓冲的channel,因此要注意“取”先于“放”
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/ 里面的一个例子很好:
同样要先输出hello world,使用有缓冲的channel和无缓冲的channel分别是这样的:
有缓冲的channel:
var a string
var c = make(chan int, 10)
func f() {
a = "hello, world"
c <- 0
}
func main() {
go f()
<-c
print(a)
}
这里有个缓冲,因此放入数据的操作c<- 0先于取数据操作 <-c
无缓冲的channel:
var a string
var c = make(chan int)
func f() {
a = "hello, world"
<-c
}
func main() {
go f()
c <- 0
print(a)
}
由于c是无缓冲的channel,因此必须保证取操作<-c 先于放操作c<- 0
参考文档:
Go语言中的channel魔法
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/
谈点对goroutine的理解
http://comments.gmane.org/gmane.comp.lang.go.china/676
goroutine效果测试
Effective Go
http://golang.org/doc/effective_go.html#goroutines
- [Cake] 0.C#Make自动化构建-简介
- [认证授权] 3.基于OAuth2的认证(译)
- [Asp.Net Core] 1. IIS中的 Asp.Net Core 和 dotnet watch
- kafka数据迁移实践
- HDFS 2.x 磁盘间数据均衡的一种可行办法
- Batik渲染png图片异常的bug修复全程记录
- Web应用服务器安全:攻击、防护与检测
- 基于Go Packet实现网络数据包的捕获与分析
- 动态追踪技术(四):基于 Linux bcc/BPF 实现 Go 程序动态追踪
- Hive 时间转换函数使用心得
- Flume-Hbase-Sink针对不同版本flume与HBase的适配研究与经验总结
- 利用Flume 汇入数据到HBase:Flume-hbase-sink 使用方法详解
- 浅谈保证软件工程质量的一些心得体会
- 基于ELK的nginx-qps监控解决方案
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Oracle RAC变更实验之修改11gR2+公网IP地址(网段不变)
- C# 纯控制台创建一个全屏窗口
- MySQL MHA部署添加Linux/Unix基本信息至Django中
- 记一次innobackupex导致的从库无法同步的问题
- mysqlbinlog命令详解记一次有函数的标量子查询导致的查询缓慢
- ctfshow红包题-web
- 微信支付一面(C++后台)
- 强网杯-随便注
- LeetCode 1547. Minimum Cost to Cut a Stick(动态规划)
- 管道符漏洞
- 06-STM32+ESP8266+AIR202远程升级方案-移植STM32+ESP8266实现利用http或https远程更新STM32程序到自己的项目(定时访问升级,备份升级)
- 反射
- 记一次sys 数据库的修复
- 使用Django管理数据库表
- php学习day3