【golang】go-channel-goroutine实践1

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

有一个资源池存储这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,负责传递的信息分别是什么。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值