當前位置:
首頁 > 知識 > goroutine 加 channel 代替遞歸調用,突破遞歸調用的層級限制

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日期、時間相關內容
設計模式解密(17)- 備忘錄模式
php nginx反向代理
log4go的日誌滾動處理——適應生產環境的需要

TAG:達人科技 |

您可能感興趣

158行Python 代碼,復現 DeepMind 遞歸神經網路 DRAW!
遞歸、歸併排序,master公式
c 和 Python 實現歸併排序(遞歸,非遞歸)
在Python程序中設置函數最大遞歸深度
可視化遞歸——你所不知道的Python之美
遞歸皮層網路RCN識別文本CAPTCHAS的Science論文基礎知識和譯文
遞歸:夢中夢 Linux 中國
php 遞歸刪除目錄下的文件
如何在使用 scp 命令時遞歸地排除文件
ICLR19高分論文:為思想「層次」建模,遞歸推理讓AI更聰明
技術的遞歸結構
遞歸函數及匿名函數配合內置函數的使用
看動畫輕鬆理解「遞歸」與「動態規劃」
關於遞歸的有趣漫畫
一個長期被誤會的問題,這下說清楚了——迭代與遞歸的性能
谷歌提出「超大數相乘」演算法,量子版遞歸有望成真!
基於遞歸神經網路的張量流時間序列分析
德羅斯特效應是一個荷蘭語辭彙,描述了一種特殊類型的遞歸圖片
人工智慧時代:什麼是遞歸神經網路
離子吸氣式電動發動機,遞歸神經網路,人造流星雨,短時爆發活動