線程(goroutine)與管道(channel)的基本使用前面兩篇文章已經介紹了,這篇文章介紹下多線程通訊與多線程操作管道。
實例
1.1、一個線程往管道里寫數據、另一個線程從管道里讀數據示例
package main import ( "fmt" "time" ) func writeChan(pi chan string) { for i := 0; i < 10; i++ { teststr := fmt.Sprintf("input channel data %s", string(i)) pi <- teststr } fmt.Println("write channel end len:", len(pi)) } func readChan(pi chan string) { var str string for i := 0; i < 10; i++ { str = <-pi fmt.Println("read channel data:", str) } } func main() { var strChan chan string // 定義管道 strChan = make(chan string, 10) // 初始化管道的長度 go writeChan(strChan) // 啟動往管道里寫數據的線程 go readChan(strChan) // 啟動從管道里讀數據的線程 time.Sleep(time.Second) // sleep 1秒,等兩個線程結束 }
1.2、多線程判斷一千以內的素數的例子
素數又叫質數,質數是指在大於1的自然數中,除了1和它本身以外,不能被其他自然數整除的數。最小的質數是2,它也是唯一的偶數質數,最前面的質數依次排列為:2、3、5、7、11、13、17、19、23、29、31等。”
package main import "fmt" func calc(taskChan chan int, resChan chan int, exitChan chan bool) { for v := range taskChan { flag := true for i :=2; i < v; i ++ { if v%i==0 { // 判斷不是素數的內容 flag = false break } } if flag { resChan <- v // 將素數寫入管道 } } fmt.Println("exit") exitChan <- true // 結束時將結束標記寫入結束的管道 } func main() { // 定義三個管道,intChan里存1000個數字,在這些數字里判斷素數 intChan := make(chan int, 1000) // resultChan里存判斷出來的素數 resultChan := make(chan int, 1000) // exitChan里存儲進程結束的信號,用來判斷子進程是否都結束了 exitChan := make(chan bool, 8) go func() { // 啟動一個線程往intChan管道里寫入1000個數 for i :=0; i < 1000; i ++ { intChan <- i } // 1000個數寫完后關閉管道(不能往管道里寫數據了、用for range循環完intChan管道后會自動退出循環) close(intChan) }() // 啟動8個攜程執行計算素數的函數 for i :=0; i < 8; i ++ { go calc(intChan, resultChan, exitChan) // calc(數據管道, 結果管道, 退出信號管道) } // 啟動一個線程,獲取所有計算素數子進程的退出新號(從退出信號管道里獲取八個退出信息號,證明八個goroutine全部退出了) go func() { for i := 0; i < 8; i ++ { <- exitChan // 只從管道里把內容取出來(不需要獲取)可以這么寫( <- exitChan),不用使用變量接,就是從管道里取出內容丟掉 fmt.Println("wait goroutine", i, "exited") } close(resultChan) // 所有計算素數的goroutine退出后關閉結果管道 }() // 循環讀取計算后得到的素數(管道關掉之后for range循環完畢之后就會自動退出循環) for v := range resultChan { fmt.Println(v) }
1.3、使用管道判斷多個子線程是否結束示例
package main import ( "fmt" ) // 往管道里寫數據的函數 func senddata(ch chan int, exitChan chan struct{}) { // 往數據管道里寫數據,寫完后關閉管道 for i := 0; i < 10; i++ { ch <- i } close(ch) // 往數據管道里寫完數據后往退出管道里寫入退出新號 var a struct{} exitChan <- a } // 從管道里讀數據的函數 func getdata(ch chan int, exitChan chan struct{}) { // 死循環讀取管道里的數據 for { // 使用死循環讀取管道里的數據時一定要通過類型斷言判斷管道關閉 v, ok := <-ch if !ok { fmt.Println("form chan get data failed") break } fmt.Println(v) } // 讀取完數據后往退出管道里寫入退出新號 var a struct{} exitChan <- a } func main() { // 初始化並實例化數據管道與結束信號管道 var pipe chan int pipe = make(chan int, 10) exitChan := make(chan struct{}, 3) // 啟動一個往管道里寫數據的子線程 go senddata(pipe, exitChan) // 啟動一個從管道里讀數據的子線程 go getdata(pipe,exitChan) // 判斷兩個子線程是否結束 var total = 0; for _ = range exitChan { total ++ if total == 2 { // 如果exitChan里有兩個數則表示兩個子線程結束了 break } } }