利用channel形成管道溝通循環內外

  • 2019 年 11 月 27 日
  • 筆記

這個要解決的問題是,比如如果有一個大循環,取自一個大的文件,要進行邏輯處理,那麼這個邏輯的程式碼要放在循環每一行的循環體裡面,這樣有可能會出現一個for循環的邏輯嵌套,一層又一層,類似俄羅斯套娃.如果放在外面那麼就需要把大循環的每一行數據存到一個數組或者切片裡面,這樣會佔很大的記憶體

那麼就可以使用這種技巧來既能解決循環嵌套,又能解決不存在佔用大記憶體的數據

創建一個channel,開啟一個goroutine,在groutine裡面進行for循環遍歷,把每一行的數據發送到channel中 在主groutine裡面,讀取channel,因為接收者總是比發送者先執行,那麼這個地方就會阻塞等待那一個數據到來 這樣就形成這樣一個良性的同步操作,雖然是在不同的groutine裡面執行的,但是總是同步執行的,並且解決了循環嵌套的問題

package main    import "fmt"    import "time"    func main() {      arr := []int{1, 2, 3, 4, 5, 6}      yields := make(chan int)      go func() {          for _, i := range arr {              //每次這裡先列印,然後跳到循環外              fmt.Println("循環內", i)              yields <- i              //這是防止執行太快看不到效果              time.Sleep(time.Second)          }          close(yields)      }()      for i := range yields {          fmt.Println("循環外:", i)      }  }

就是這樣的效果

循環內 1  循環外: 1  循環內 2  循環外: 2  循環內 3  循環外: 3  循環內 4  循環外: 4  循環內 5  循環外: 5  循環內 6  循環外: 6

如果那個channel是個有快取的channel,就會先把快取數量的全都塞進channel,後循環外才執行,這個在很多的案例里都有使用

yields := make(chan int, 6)  循環內 1  循環內 2  循環內 3  循環內 4  循環內 5  循環內 6  循環外: 1  循環外: 2  循環外: 3  循環外: 4  循環外: 5  循環外: 6

比如說這樣的程式碼:

    mailboxes := make(chan *imap.MailboxInfo, 20)      go func() {          imapClient.List("", "*", mailboxes)      }()      //列取郵件夾      for m := range mailboxes {          mailDirs = append(mailDirs, m.Name)      }

這個很像是PHP中的yield的作用,溝通函數內外

Tags: