go17---并发

yjf512 · 2015-02-21 11:09:07 · 1076 次点击 · 预计阅读时间 2 分钟 · 大约1分钟之前 开始浏览    
这是一个创建于  2015-02-21 11:09:07 的文章,其中的信息可能已经有所发展或是发生改变。

当被问到为什么用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语言》中的一个例子说明。

clip_image001

这里的第18行为什么要sleep? 这里是为了等上面两个go ready处理完成。

 

好了,这里就出来了一个需求:一个goroutine结束后必须要向主线程传输数据,告诉主线程这个goroutine已经结束了。

 

这里就引进了channel的概念

channel的使用

channel的意思用白话可以这么理解:主线程告诉大家你开goroutine可以,但是我在我的主线程开了一个管道,你做完了你要做的事情之后,往管道里面塞个东西告诉我你已经完成了。

上面的例子就可以改为:

clip_image002

从这个程序得到的几点信息:

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效果测试

http://webcache.googleusercontent.com/search?q=cache:Vwa9TGfQKtoJ:blog.weizhe.net/tag/goroutine%2520golang+&cd=6&hl=en&ct=clnk

Effective Go

http://golang.org/doc/effective_go.html#goroutines

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书作者带你一步一步深入这些方法。你将理解 Go语言为何选定这些并发模型,这些模型又会带来什么问题,以及你如何组合利用这些模型中的原语去解决问题。学习那些让你在独立且自信的编写与实现任何规模并发系统时所需要用到的技巧和工具。 理解Go语言如何解决并发难以编写正确这一根本问题。 学习并发与并行的关键性区别。 深入到Go语言的内存同步原语。 利用这些模式中的原语编写可维护的并发代码。 将模式组合成为一系列的实践,使你能够编写大规模的分布式系统。 学习 goroutine 背后的复杂性,以及Go语言的运行时如何将所有东西连接在一起。 作者简介 · · · · · · Katherine Cox-Buday是一名计算机科学家,目前工作于 Simple online banking。她的业余爱好包括软件工程、创作、Go 语言(igo、baduk、weiquei) 以及音乐,这些都是她长期的追求,并且有着不同层面的贡献。 目录 · · · · · · 前言 1 第1章 并发概述 9 摩尔定律,Web Scale和我们所陷入的混乱 10 为什么并发很难? 12 竞争条件 13 原子性 15 内存访问同步 17 死锁、活锁和饥饿 20 确定并发安全 28 面对复杂性的简单性 31 第2章 对你的代码建模:通信顺序进程 33 并发与并行的区别 33 什么是CSP 37 如何帮助你 40 Go语言的并发哲学 43 第3章 Go语言并发组件 47 goroutine 47 sync包 58 WaitGroup 58 互斥锁和读写锁 60 cond 64 once 69 池 71 channel 76 select 语句 92 GOMAXPROCS控制 97 小结 98 第4章 Go语言的并发模式 99 约束 99 for-select循环103 防止goroutine泄漏 104 or-channel 109 错误处理112 pipeline 116 构建pipeline的最佳实践 120 一些便利的生成器 126 扇入,扇出 132 or-done-channel 137 tee-channel 139 桥接channel模式 140 队列排队143 context包 151 小结 168 第5章 大规模并发 169 异常传递169 超时和取消 178 心跳 184 复制请求197 速率限制199 治愈异常的goroutine 215 小结 222 第6章 goroutine和Go语言运行时 223 工作窃取223 窃取任务还是续体 231 向开发人员展示所有这些信息 240 尾声 240 附录A 241
好的,下面我来为您演示一下如何使用 go-streams 进行并发控制。 首先,您需要安装 go-streams,可以通过以下命令进行安装: ``` go get github.com/reugn/go-streams ``` 接下来,我们可以使用 go-streams 提供的 `ConcurrentStreamBuilder` 和 `ConcurrentSinkBuilder` 来实现并发控制。 假设我们有一个需要处理的数据流,可以使用 `go-streams` 中的 `NewStreamBuilder` 来创建一个数据流: ```go streamBuilder := go_streams.NewStreamBuilder() ``` 然后,我们可以使用 `ConcurrentStreamBuilder` 来将数据流转换为并发处理的数据流,例如: ```go concurrentStreamBuilder := go_streams.NewConcurrentStreamBuilder(streamBuilder, 10) ``` 这里我们设置并发度为 10,表示最多会有 10 个 goroutine 同时处理数据。 接下来,我们需要为并发处理添加一个 Sink,可以使用 `ConcurrentSinkBuilder` 来创建: ```go concurrentSinkBuilder := go_streams.NewConcurrentSinkBuilder(concurrentStreamBuilder, 10) ``` 这里我们同样设置并发度为 10。 最后,我们可以将数据源和 Sink 连接起来,开始处理数据: ```go source := go_streams.NewSliceSource(data) sink := concurrentSinkBuilder.Build() source.Process(sink) ``` 这里的 `data` 可以是任何实现了 `Iterator` 接口的数据类型,例如 Go 中的数组、切片、映射或通道等。 以上就是使用 go-streams 进行并发控制的基本示例。如果您有其他问题或需要更详细的说明,请随时提问,我将尽力为您解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值