如何使用 channel
如何使用 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的更多相关文章
- Golang, 以17个简短代码片段,切底弄懂 channel 基础
(原创出处为本博客:http://www.cnblogs.com/linguanh/) 前序: 因为打算自己搞个基于Golang的IM服务器,所以复习了下之前一直没怎么使用的协程.管道等高并发编程知识 ...
- TODO:Go语言goroutine和channel使用
TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...
- GO语言之channel
前言: 初识go语言不到半年,我是一次偶然的机会认识了golang这门语言,看到他简洁的语法风格和强大的语言特性,瞬间有了学习他的兴趣.我是很看好go这样的语言的,一方面因为他有谷歌主推,另一方面他确 ...
- Critical: Update Your Windows Secure Channel (cve-2014-6321,MS14-066)
前言:风雨欲来山满楼,下半年开始各种凶猛的漏洞层出不穷,天下已经不太平,互联网已经进入一个新的台阶 0x01 cve-2014-6321 11月的补丁月,微软请windows的用户吃了顿大餐,发布了1 ...
- JAVA NIO Channel
Basic: 多数通道都是链接到开发的文件描述符的.Channel类提供维持平台独立性的抽象过程. 通道是一种途径,访问和操作操作系统,缓冲区是数据操作点: Channel类继承结构图: 通过 ...
- channel Golang
Golang, 以17个简短代码片段,切底弄懂 channel 基础 (原创出处为本博客:http://www.cnblogs.com/linguanh/) 前序: 因为打算自己搞个基于Golang的 ...
- go channel
channel 是go语言中不同goroutine之间通信一种方法 //定义一个channel c := make(chan bool) //向channel中写入 c <- true //读取 ...
- [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 ...
- 图解Netty之Pipeline、channel、Context之间的数据流向。
声明:本文为原创博文,禁止转载. 以下所绘制图形均基于Netty4.0.28版本. 一.connect(outbound类型事件) 当用户调用channel的connect时,会发起一个 ...
- go:channel(未完)
注:1)以下的所有讨论建立在包含整形元素的通道类型之上,即 chan int 2)对于“<-”我的理解是,它可能是一个操作符(接收操作符),也 可能是类型的一部分(如“chan<- in ...
随机推荐
- java分割函数split的用法(二)
package com.b; public class Sysetm { public static void main(String[] args) { String a=new String(&q ...
- JS面向对象编程,对象,属性,方法。
document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...
- Linux系统层面标配
1.MySQL中出现存SWAP,主要会是哪些原因?--物理内存切实不足--numa导致内存分配不均,出现物理内存未使用完,就出现大量swap的使用 2.MySQ中CPU负载很高,是什么原因?给出查找的 ...
- Rest之路 - 第一个Rest程序
在 Eclipse 里新建一个 Dynamic project 将 Jersey 的 jar 包,拷贝到 WebContent -> WEB-INF -> lib 文件夹 Add jars ...
- dB2 索引相关
ALTER TABLE "XXXX"."tableA" PCTFREE 20 ; CREATE INDEX "schema"."X ...
- vs2017 android demo
vs2017自安装以后就没怎么打开过,虽然12出的时候用10,15出的时候用13,17出的时候用15,但我依然坚持不用也装上再说的理念. 1.vs2017开发IOS和Android安装所必不可少的,u ...
- 易酷cms本地包含漏洞拿shell
测试版本:易酷cms2.5 包含一句话:http://localhost/ekucms2.5/?s=my/show/id/{~eval($_POST[x])} 会在网站的/temp/Logs/目录下生 ...
- 第十一章 SpringMvc(待续)
············
- Linux系统SCSI磁盘扫描机制解析及命令实例(转)
转载请在文首保留原文出处:EMC中文支持论坛 介绍 Linux系统扫描SCSI磁盘有几种方式?Linux新增LUN之后,能否不重启主机就认出设备?如果安装了PowerPath,动态添加/删除LUN的命 ...
- latex中如何引用公式
在使用latex编辑文章时,经常会需要引用公式.图表等等. 如果我们人为地对这些公式.图表进行编号1-2-3-4,然后在文章中使用Eq(1)-Eq(2)-Eq(3)-Eq(4)去引用这些公式,固然是可 ...