Golang 併發的退出

Golang 併發的退出

《The Go Programming Language》筆記

關閉一個channel,操作channel之後的程式碼可以立即被執行,並且會產生零值。

廣播機制:用關閉一個channel來進行廣播。建立一個退出channel,不會向這個channel傳送任何值。

import ( “flag” “fmt” “io/ioutil” “os” “path/filepath” “sync” “time”)//一個已經被關閉的channel不會阻塞,已經被關閉的channel會實時返回//goroutine退出,關閉done來進行廣播var done = make(chan struct{})//判斷done是否關閉,即是否執行goroutine退出func cancelled() bool { select { case <-done: return true default: return false }}//獲取目錄dir下的檔案大小func walkDir(dir string, wg *sync。WaitGroup, fileSizes chan<- int64) { defer wg。Done() if cancelled() { return } for _, entry := range dirents(dir) { if entry。IsDir() { //目錄 wg。Add(1) subDir := filepath。Join(dir, entry。Name()) go walkDir(subDir, wg, fileSizes) } else { fileSizes <- entry。Size() } }}//sema is a counting semaphore for limiting concurrency in direntsvar sema = make(chan struct{}, 20)//讀取目錄dir下的檔案資訊func dirents(dir string) []os。FileInfo { select { case sema <- struct{}{}: //acquire token case <-done: return nil // cancelled } defer func() { <-sema }() //release token entries, err := ioutil。ReadDir(dir) if err != nil { fmt。Fprintf(os。Stderr, “du: %v\n”, err) return nil } return entries}//輸出檔案數量的大小func printDiskUsage(nfiles, nbytes int64) { fmt。Printf(“%d files %。1f GB\n”, nfiles, float64(nbytes)/1e9)}//提供-v 引數會顯示程式進度資訊var verbose = flag。Bool(“v”, false, “show verbose progress messages”)func Start() { flag。Parse() roots := flag。Args() //需要統計的目錄 if len(roots) == 0 { roots = []string{“。”} } fileSizes := make(chan int64, 5) var wg sync。WaitGroup for _, root := range roots { wg。Add(1) go walkDir(root, &wg, fileSizes) } go func() { os。Stdin。Read(make([]byte, 1)) //從標準輸入讀取一個字元,執行goroutine退出 close(done) }() go func() { wg。Wait() //等待goroutine結束 close(fileSizes) }() var tick <-chan time。Time if *verbose { tick = time。Tick(100 * time。Millisecond) //輸出時間間隔 } var nfiles, nbytes int64loop: for { select { case <-done: //to allow existing goroutines to finish for range fileSizes { //fileSizes關閉時,for迴圈會自動結束 //Do nothing } return case size, ok := <-fileSizes: if !ok { break loop } nfiles++ nbytes += size case <-tick: printDiskUsage(nfiles, nbytes) } } printDiskUsage(nfiles, nbytes)}