zoukankan      html  css  js  c++  java
  • goroutine 加 channel 代替递归调用,突破递归调用的层级限制

     1 package main
     2 
     3 import (
     4     "fmt"
     5     "github.com/davecgh/go-spew/spew"
     6     "github.com/BurntSushi/toml"
     7     "errors"
     8     "sync"
     9 )
    10 
    11 type kvData struct {
    12     Prefix string // 前缀
    13     Data map[string]interface{}
    14 }
    15 
    16 // 递归将所有的层级遍历出来
    17 func unmarshal(m kvData, work chan kvData, result chan []map[string]interface{}, wg *sync.WaitGroup) (error) {
    18     defer wg.Done()
    19     var r []map[string]interface{}
    20     for k, v := range m.Data {
    21         switch v.(type) {
    22         case string, int64, float64, bool:
    23             r = append(r, map[string]interface{}{"k":m.Prefix + k, "v":v})
    24         case map[string]interface{}:
    25             wg.Add(2)
    26             work <- kvData{Prefix:m.Prefix + k + ".", Data : v.(map[string]interface{})}
    27         default:
    28             return errors.New("目前只能识别string、int、float、bool类型的配置")
    29         }
    30     }
    31 
    32     result <- r
    33 
    34     return nil
    35 }
    36 
    37 func main() {
    38     text := `
    39 myip = "1.1.4.51"
    40 type = "red"
    41 [server]
    42   [server.http]
    43     addr="1.11.7.1:5"
    44   [server.grpc]
    45     addr="1.1.1.1:5"`
    46 
    47     var obj map[string]interface{}
    48 
    49     if e := toml.Unmarshal([]byte(text), &obj); e != nil {
    50         spew.Dump(e)
    51     }
    52 
    53 
    54 
    55     var work = make(chan kvData, 30)
    56     var result = make(chan []map[string]interface{}, 30)
    57     var wg sync.WaitGroup
    58 
    59     var r []map[string]interface{}
    60 
    61     wg.Add(2)
    62     if e := unmarshal(kvData{Prefix:"", Data:obj}, work, result, &wg); e != nil {
    63         fmt.Println(e)
    64         return
    65     }
    66 
    67     var end = make(chan int)
    68     go func() {
    69         for {
    70             select {
    71             case newWork := <-work:
    72                 fmt.Println("w")
    73                 spew.Dump(newWork)
    74                 go unmarshal(newWork, work, result, &wg)
    75             case newResult := <-result:
    76                 wg.Done()
    77                 fmt.Println("r")
    78                 spew.Dump(newResult)
    79                 if len(newResult) != 0 {
    80                     r = append(r, newResult...)
    81                 }
    82             case <-end:
    83                 spew.Dump(r)
    84                 return
    85             }
    86         }
    87     }()
    88     wg.Wait()
    89     end<-1
    90 
    91     fmt.Println("--all----
    ")
    92     for _, v := range r {
    93         fmt.Println(" k => ", v["k"])
    94         fmt.Println(" v => ", v["v"])
    95     }
    96 
    97     return
    98 }

    1、创建两个channel(work,result)分别用来存放任务、返回结果。
    2、创建一个结构体 kvData 来存放任务以及任务执行的环境依赖。
    3、创建sync.WaitGroup 来等待所有的 goroutine 执行完成。

    限制递归层级的原因就是递归的栈的释放是从最后一层倒退着向上释放的,其实限制递归层级的条件就是栈的容量。
    goroutine 加 channel 在没层级的过程中都会将结果放回到结果的channel(result)、如果需要进一步分析就将需要进一步分析的任务放到 channel(work)中
    一方面是并发在执行、一方面是不会造成栈的累积,因此不存在层级的限制。

    注:
    1、递归在数量比较少的时候速度和内存的占用量是比较好的(没有做具体的实验所有没有具体的数据)
    2、goroutine 启动的时候大概需要占用4K的内容,针对于这样的递归来说还是比较大的一个开销
    3、goroutine 应该做一个pool,然后反复使用

    不断学习,做更好的自己!
  • 相关阅读:
    mysql备份还原
    java-mysql(3) 读写image
    java-mysql(2) Prepared statement
    java-mysql(1)
    jmeter报告分析工具
    浏览器下载img标签Base64图片
    Java定时器TimeTask
    js倒计时
    h5语音播放(移动端)
    Linux环境下在Tomcat上部署JavaWeb工程
  • 原文地址:https://www.cnblogs.com/moontower/p/7281999.html
Copyright © 2011-2022 走看看