如何使用 Channel

例子来自于Concurrency is not parallelism

Google Search: A fake framework

v1.0

var (
Web = fakeSearch("web")
Image = fakeSearch("image")
Video = fakeSearch("video")
) type Search func(query string) Result func fakeSearch(kind string) Search {
return func(query string) Result {
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
return Result(fmt.Sprintf("%s result for %q\n", kind, query))
}
}
func main() {
rand.Seed(time.Now().UnixNano())
start := time.Now()
results := Google("golang")
elapsed := time.Since(start)
fmt.Println(results)
fmt.Println(elapsed)
}

关键函数

func Google(query string) (results []Result) {
results = append(results, Web(query))
results = append(results, Image(query))
results = append(results, Video(query))
return
}

Google 2.0

每个 search, 独立并发.

No locks. No condition variables. No callbacks.

func Google(query string) (results []Result) {
c := make(chan Result)
go func() { c <- Web(query) } ()
go func() { c <- Image(query) } ()
go func() { c <- Video(query) } () for i := 0; i < 3; i++ {
result := <-c
results = append(results, result)
}
return
}

Google 2.1

如果某个服务比较慢,怎么办?

No locks. No condition variables. No callbacks.

func Google(query string) (results []Result) {
c := make(chan Result)
go func() { c <- Web(query) } ()
go func() { c <- Image(query) } ()
go func() { c <- Video(query) } () timeout := time.After(80 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case result := <-c:
results = append(results, result)
case <-timeout:
fmt.Println("timed out")
return
}
}
return
}

Google 3.0 Avoid timeout

No locks. No condition variables. No callbacks.

func First(query string, replicas ...Search) Result {
c := make(chan Result)
searchReplica := func(i int) { c <- replicas[i](query) }
for i := range replicas {
go searchReplica(i)
}
return <-c
}
func Google(query string) (results []Result) {
c := make(chan Result)
go func() { c <- First(query, Web1, Web2) } ()
go func() { c <- First(query, Image1, Image2) } ()
go func() { c <- First(query, Video1, Video2) } ()
timeout := time.After(80 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case result := <-c:
results = append(results, result)
case <-timeout:
fmt.Println("timed out")
return
}
}
return
}

Google 3.1

上面的例子看起来挺完美,但是存在一个严重的内存泄漏,不知道你看出来没有.

First 中的 searchReplica调用,除了第一个会成功返回以外,其他都不会返回.因为堵塞在 c 上面,从而导致了内存泄漏.

改进也很简单

func First(query string, replicas ...Search) Result {
c := make(chan Result,len(replicas)) //看似多分配了资源,但是很快就会收回
searchReplica := func(i int) { c <- replicas[i](query) }
for i := range replicas {
go searchReplica(i)
}
return <-c
}

经过简单的替换,通过 Go 的并发模型,将一个慢的,顺序执行的,故障敏感的程序改造为了一个快速的,并发的,有冗余的,健壮的程序.

完整的 google 3.1

var (
Web1 = fakeSearch("web")
Web2 = fakeSearch("web")
Image1 = fakeSearch("image")
Image2 = fakeSearch("image")
Video1 = fakeSearch("video")
Video2 = fakeSearch("video")
) type Search func(query string) Result func fakeSearch(kind string) Search {
return func(query string) Result {
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
return Result(fmt.Sprintf("%s result for %q\n", kind, query))
}
}
func main() {
rand.Seed(time.Now().UnixNano())
start := time.Now()
results := Google("golang")
elapsed := time.Since(start)
fmt.Println(results)
fmt.Println(elapsed)
} func First(query string, replicas ...Search) Result {
c := make(chan Result,len(replicas))
searchReplica := func(i int) { c <- replicas[i](query) }
for i := range replicas {
go searchReplica(i)
}
return <-c
}
func Google(query string) (results []Result) {
c := make(chan Result)
go func() { c <- First(query, Web1, Web2) } ()
go func() { c <- First(query, Image1, Image2) } ()
go func() { c <- First(query, Video1, Video2) } ()
timeout := time.After(80 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case result := <-c:
results = append(results, result)
case <-timeout:
fmt.Println("timed out")
return
}
}
return
}

如何使用 channel的更多相关文章

  1. Golang, 以17个简短代码片段,切底弄懂 channel 基础

    (原创出处为本博客:http://www.cnblogs.com/linguanh/) 前序: 因为打算自己搞个基于Golang的IM服务器,所以复习了下之前一直没怎么使用的协程.管道等高并发编程知识 ...

  2. TODO:Go语言goroutine和channel使用

    TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...

  3. GO语言之channel

    前言: 初识go语言不到半年,我是一次偶然的机会认识了golang这门语言,看到他简洁的语法风格和强大的语言特性,瞬间有了学习他的兴趣.我是很看好go这样的语言的,一方面因为他有谷歌主推,另一方面他确 ...

  4. Critical: Update Your Windows Secure Channel (cve-2014-6321,MS14-066)

    前言:风雨欲来山满楼,下半年开始各种凶猛的漏洞层出不穷,天下已经不太平,互联网已经进入一个新的台阶 0x01 cve-2014-6321 11月的补丁月,微软请windows的用户吃了顿大餐,发布了1 ...

  5. JAVA NIO Channel

    Basic:   多数通道都是链接到开发的文件描述符的.Channel类提供维持平台独立性的抽象过程.   通道是一种途径,访问和操作操作系统,缓冲区是数据操作点: Channel类继承结构图: 通过 ...

  6. channel Golang

    Golang, 以17个简短代码片段,切底弄懂 channel 基础 (原创出处为本博客:http://www.cnblogs.com/linguanh/) 前序: 因为打算自己搞个基于Golang的 ...

  7. go channel

    channel 是go语言中不同goroutine之间通信一种方法 //定义一个channel c := make(chan bool) //向channel中写入 c <- true //读取 ...

  8. [bigdata] flume file channel CPU消耗比 memory channel高的原因

    https://www.quora.com/Why-does-flume-take-more-resource-CPU-when-file-channel-is-used-compared-to-wh ...

  9. 图解Netty之Pipeline、channel、Context之间的数据流向。

    声明:本文为原创博文,禁止转载.       以下所绘制图形均基于Netty4.0.28版本. 一.connect(outbound类型事件)  当用户调用channel的connect时,会发起一个 ...

  10. go:channel(未完)

    注:1)以下的所有讨论建立在包含整形元素的通道类型之上,即 chan int 2)对于“<-”我的理解是,它可能是一个操作符(接收操作符),也  可能是类型的一部分(如“chan<- in ...

随机推荐

  1. Cassandra学习六 一些知识点

    http://www.flyml.net/2016/09/08/cassandra-tutorial-java-api-example/ Cassandra对查询的支持很弱,只支持主键列及索引列的查询 ...

  2. Linux - 归档和压缩

    归档 归档就是将多个文件或目录合并成一个文件 归档的目的就是方便备份.还原及文件的传输操作 tar 命令:将多个文件或目录归档到一个文件中,可以根据需要只还原归档文件中的某些指定的文件 c:创建,v: ...

  3. java成神之——集合框架之队列,栈,集合并发

    集合 队列和双端队列 PriorityQueue Deque BlockingQueue Queue 栈 集合并发 线程锁 线程安全集合 结语 集合 队列和双端队列 PriorityQueue 此队列 ...

  4. Git第三方仓库安装方式(IUS)

    1.安装使用里面说的自动化安装脚本 curl https://setup.ius.io | sh 2.然后可以看到 git2u相关内容 yum search git 3.执行安装,并查看下版本 yum ...

  5. flask系列二之基础知识

    一.调试模式(debug模式) 1.设置debug模式 在app.run()中传入关键字参数debug,app.run(debug=Ture),就设置当前项目为debug模式.如下所示: # 从fla ...

  6. 配置key认证登陆Ubuntu (下)

    梗概: 使用证书登陆,可以减少密码的使用,避免密码泄露,证书登陆更加方便.安全. Secure CRT 和Putty 原理相同,生成 密钥对(Key pair)操作有所不同. 1.生成key pair ...

  7. FFmpeg新版本(2016年10月份以后) 支持硬件解码

    FFmpeg provides a subsystem for hardware acceleration. Hardware acceleration allows to use specific ...

  8. WordPress,discuz 根据不同的入口url更换logo

    Discuz!中调用cookie的思路出来了:    设置cookie:dsetcookie('cookie名', 'cookie值', '有效时间'); 读取cookie有两种方法,第一种使用get ...

  9. Tornado之抽屉实战(3)--注册

    知识点应用:标签绑定事件,jQuery获取用户值-->AJAX发送数据-->后台路由系统-->业务逻辑处理-->ORM数据操作-->write返回-->AJAX回调 ...

  10. xcode中的预定义宏

    [xcode中的预定义宏] 1.SRCROOT,是定义本target的proj的路径. 2.OBJROOT,对象文件根路径,对象文件(即obj文件)就是中间的临时文件.中间文件输出目录的名字以“pro ...