分享
  1. 首页
  2. 文章

go-channel实践1

niyuelin1990 · · 1580 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

某些信息从旧的资源池中取出来,经过一些加工处理,再放入新的资源池中,这个过程如果按传统的方式就是采用完全串行的方式效率会很低,粒度太粗了,具体的粒度可以细化以每次所取的单位资源为粒度。

有一个资源池存储这person的信息,将每个person从中取出来,之后进行一些处理,再存到新的资源池中,这里用oldarray以及newarray来模拟旧的和新的资源池:

代码如下:


type Person struct {
 name string
age int
addr string
}
var oldpersonarray = [5]Person{}
var newpersonarray = [5]Person{}
type PersonHandler interface {
 Batch(origs <-chan Person) <-chan Person
 Handle(orig *Person)
}
//struct 实现了personhandler 接口
type PersonHandlerImpl struct{}
//从origs接收信息 处理之后再返回给新的channel
func (handler PersonHandlerImpl) Batch(origs <-chan Person) <-chan Person {
 dests := make(chan Person, 100)
 go func() {
 for {
 p, ok := <-origs
 if !ok {
 close(dests)
 break
}
 handler.Handle(&p)
 log.Printf("old value : %v\n", p)
 //time.Sleep(time.Second)
dests <- p
 }
 }()
 return dests
}
//这里要使用引用传递
func (handler PersonHandlerImpl) Handle(orig *Person) {
 orig.addr = "new address"
}
func getPersonHandler() PersonHandler {
 return &PersonHandlerImpl{}
}
//print the oldpersonarray into the chan<-Person
func fetchPerson(origs chan<- Person) {
 for _, v := range oldpersonarray {
 fmt.Printf("get the value : %v \n", v)
 time.Sleep(time.Second)
 origs <- v
 }
 close(origs)
}
//fetch the value from the channel and store it into the newpersonarray
func savePerson(dest <-chan Person) <-chan int {
 intChann := make(chan int)
 go func() {
 index := 0
for {
 p, ok := <-dest
 if !ok {
 break
}
 time.Sleep(time.Second)
 log.Printf("new value transfer %v \n", p)
 newpersonarray[index] = p
 index++
 }
 intChann <- 1
}()
 return intChann
}
func init() {
 //使用range的话是值传递 这里要给oldpersonarray赋值进来
tmplen := len(oldpersonarray)
 for i := 0; i < tmplen; i++ {
 oldpersonarray[i].addr = "old address"
oldpersonarray[i].age = i
 oldpersonarray[i].name = strconv.Itoa(i)
 }
 log.Printf("first print init value : %v\n", oldpersonarray)
}
func main() {
 handeler := getPersonHandler()
 origs := make(chan Person, 100)
 dests := handeler.Batch(origs)
 go func() { fetchPerson(origs) }()
 // 不加go func的话 要等这句执行完 才能执行下一句
 // 则orgis信息都输出 完全关闭掉 这个时候 从dest接收信息的语句才开始执行
 // 所以不会动态输出 这句加上go func的话 就会没隔 1s 动态输出
 // 如果将fetchPerson 再往前面放一句 则old value也不会动态输出
 //fetchPerson(origs)
sign := savePerson(dests)
 log.Println(<-sign)
 log.Printf("last print new value : %v \n", newpersonarray)
}

  • 首先声明一个 PersonHandler 的接口,之后声明一个struct PersonHandlerImpl 将接口中的两个方法都实现了,init函数用于进行oldarray的初始化工作。注意为了减少出错,内部的函数在方声明的时候都是单向的channel。
  • 1,2 fetchperson从oldarray中区数据,并把数据存到origs channel中,注意最后取完数据到通道之后,要由发送方将channel关闭,否则可能造成deadlock。注意在main函数中,如果fech操作没有放到一个goroutine中来执行,就仍然是串行的,相当于是把数据都放入到channel中,另一端才开始取,没发挥出并发的优势。
  • 3,4 Batch函数将person信息从origs中取出来,进行处理后,同时传到dests中,最后将dests返回,注意这里不是全部传入之后才将dests返回,而是新启动一个goroutine执行传入操作,同时将dests返回,注意要主动关闭channel。
  • 5 savePerson操作接收一个<-chann 之后从中接受person信息,将值写入到新的资源池中,最后全部写入结束之后,传一个sign channel给主进程,结束。
  • 总结,在需要动态输出信息的时候,goroutine往往是和channel结合在一起使用。最常见的用法是,一个goroutine负责向channel中写入数据,之后将channel返回,由其他进程取出信息。比如之前写过的一些websocket从前台接受信息,后台处理信息之后再动态返回给前台打出结果的模型,就和这个差不多,总之具体的异步执行流程要理清楚,都有哪些channel,负责传递的信息分别是什么。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:niyuelin1990

查看原文:go-channel实践1

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1580 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏