package main

 import (
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/BurntSushi/toml"
"errors"
"sync"
) type kvData struct {
Prefix string // 前缀
Data map[string]interface{}
} // 递归将所有的层级遍历出来
func unmarshal(m kvData, work chan kvData, result chan []map[string]interface{}, wg *sync.WaitGroup) (error) {
defer wg.Done()
var r []map[string]interface{}
for k, v := range m.Data {
switch v.(type) {
case string, int64, float64, bool:
r = append(r, map[string]interface{}{"k":m.Prefix + k, "v":v})
case map[string]interface{}:
wg.Add(2)
work <- kvData{Prefix:m.Prefix + k + ".", Data : v.(map[string]interface{})}
default:
return errors.New("目前只能识别string、int、float、bool类型的配置")
}
} result <- r return nil
} func main() {
text := `
myip = "1.1.4.51"
type = "red"
[server]
[server.http]
addr="1.11.7.1:5"
[server.grpc]
addr="1.1.1.1:5"` var obj map[string]interface{} if e := toml.Unmarshal([]byte(text), &obj); e != nil {
spew.Dump(e)
} var work = make(chan kvData, 30)
var result = make(chan []map[string]interface{}, 30)
var wg sync.WaitGroup var r []map[string]interface{} wg.Add(2)
if e := unmarshal(kvData{Prefix:"", Data:obj}, work, result, &wg); e != nil {
fmt.Println(e)
return
} var end = make(chan int)
go func() {
for {
select {
case newWork := <-work:
fmt.Println("w")
spew.Dump(newWork)
go unmarshal(newWork, work, result, &wg)
case newResult := <-result:
wg.Done()
fmt.Println("r")
spew.Dump(newResult)
if len(newResult) != 0 {
r = append(r, newResult...)
}
case <-end:
spew.Dump(r)
return
}
}
}()
wg.Wait()
end<-1 fmt.Println("--all----\n")
for _, v := range r {
fmt.Println(" k => ", v["k"])
fmt.Println(" v => ", v["v"])
} return
}

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

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

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

goroutine 加 channel 代替递归调用,突破递归调用的层级限制的更多相关文章

  1. php之递归调用,递归创建目录

    /* 递归自身调用自身,每次调用把问题简化,直到问题解决 即:把大的任务拆成相同性质的多个小任务完成 */ /* function recsum($n){ if($n>1){ return $n ...

  2. Python基础_函数闭包、调用、递归

    这节的主要内容是函数的几个用法闭包,调用.递归. 一.函数闭包 对闭包更好的理解请看:https://www.cnblogs.com/Lin-Yi/p/7305364.html 我们来看一个简单的例子 ...

  3. 为什么你学不会递归?告别递归,谈谈我的一些经验 关于集合中一些常考的知识点总结 .net辗转java系列(一)视野 彻底理解cookie,session,token

    为什么你学不会递归?告别递归,谈谈我的一些经验   可能很多人在大一的时候,就已经接触了递归了,不过,我敢保证很多人初学者刚开始接触递归的时候,是一脸懵逼的,我当初也是,给我的感觉就是,递归太神奇了! ...

  4. [转帖]go 的goroutine 以及 channel 的简介.

    进程,线程的概念在操作系统的书上已经有详细的介绍.进程是内存资源管理和cpu调度的执行单元.为了有效利用多核处理器的优势,将进程进一步细分,允许一个进程里存在多个线程,这多个线程还是共享同一片内存空间 ...

  5. Go--关于 goroutine、channel

    Go--关于 goroutine.channel goroutine 协程是一种轻量化的线程,由Go编译器进行优化. Go协程具有以下特点: 有独立的栈空间 共享程序堆中的空间 调度由用户控制 如果主 ...

  6. 求字符串长度之递归与非递归的C语言实现

    在上一篇中介绍了字符串拷贝的递归与非递归的实现,这里就不在赘述递归原理. 递归求字符串长度_strlen: 1 int _strlen(const char *src) 2 { 3 if( src = ...

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

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

  8. Go基础--goroutine和channel

    goroutine 在go语言中,每一个并发的执行单元叫做一个goroutine 这里说到并发,所以先解释一下并发和并行的概念: 并发:逻辑上具备同时处理多个任务的能力 并行:物理上在同一时刻执行多个 ...

  9. 记住经典的斐波拉契递归和阶乘递归转换为while规律

    记住经典的斐波拉契递归和阶乘递归转换为while规律.它为实现更复杂转换提供了启发性思路. # 斐波拉契--树形递归 def fab(n): if n<3: return n return fa ...

随机推荐

  1. [转] .NET领域驱动设计—看DDD是如何运用设计模式颠覆传统架构

    阅读目录: 1.开篇介绍 2.简单了解缘由(本文的前期事宜) 3.DomainModel扩展性(运用设计模式设计模型变化点) 3.1.模型扩展性 3.2.设计模式的使用(苦心专研的设计模式.设计思想可 ...

  2. navicat 连接oracle数据库报错:ORA-28547:connection to server failed,probable Oracle Net admin error

    链接:http://pan.baidu.com/s/1dEO9qJR 密码:ye2c 用Navicat连接Oracle数据库时出现如下错误 上网一查原来是oci.dll版本不对.因为Navicat是通 ...

  3. 浅谈Swift和OC的区别

    前言 转眼Swift3都出来快一年了,从OC到Swift也经历了很多,所以对两者的一些使用区别也总结了一点,暂且记录下,权当自己的一个笔记. 当然其中一些区别可能大家都有耳闻,所以这里也会结合自身的一 ...

  4. 开发抓包工具 Mac charles 3.11.5 破解版 安装包

    摘要 在发开过程中,追踪请求和监控请求与返回数据是我们经常会需要的一个需求,在Mac端,Charles是一款非常易用的抓包工具. 一.简介 Charles是Mac端的一款截取与分析网络请求的工具,在网 ...

  5. memcache基础

    一.Memcache是一种缓存技术(内存),你可以把它想像成一张巨大的内存表,形式如下[它就是一个服务] key value key值(字符串) 可以放(字符串[二进制数据[视频.音频.图片]],数值 ...

  6. nginx常用配置系列-HTTPS配置

    接上篇,nginx配置系列 HTTPS现在已经很流行,特别是AppStore上线的应用要求使用HTTPS进行通信,出于安全考虑也应该使用HTTPS,HTTPS配置需要准备证书文件,现在也有很多免费证书 ...

  7. CSS3学习系列之背景相关样式(二)

    在border-radius属性中指定两个半径 在border-radius属性中,可以指定两个半径,指定方法如下所示: border-radius:40px 20px; 针对这种情况,各种浏览器的处 ...

  8. HTML5+CSS3实现的响应式垂直时间轴

    <!DOCTYPE HTML><html><head><meta charset="utf-8"><meta name=&qu ...

  9. Windows PowerShell 默认颜色

    屏幕背景:1,36,86 屏幕文字:238,237,240 弹出文字:0,128,128 弹出窗口背景:255,255,255

  10. Python开发简单爬虫(一)

    一 .简单爬虫架构: 爬虫调度端:启动爬虫,停止爬虫,监视爬虫运行情况 URL管理器:对将要爬取的和已经爬取过的URL进行管理:可取出带爬取的URL,将其传送给“网页下载器” 网页下载器:将URL指定 ...