ex1
package main
/*
goroutine 是由GO運行時管理的輕量級線程
go f(x,y, z) 就啟動了一個goroutine, 其中f,x,y,z在當(dāng)前goroutine中立即計算, f內(nèi)容的執(zhí)行在另一個新goroutine中。
所有的goroutine都是運行在同一個地址空間中, 所有訪問共享內(nèi)存時,必須進(jìn)行同步處理。
在sync包中上, 提供了同步需要的原語
*/
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
ex2
package main
/*
Channels 就管道,就是劇導(dǎo)管, 你可能管道操作符進(jìn)行讀寫, 操作符為 <-
ch <- v // 把 v 寫入管道
v := <-ch // 從 ch 管道中讀出到 v 變量中
數(shù)據(jù)的流向, 就箭頭的指向。
所有 maps , slices, channels 復(fù)雜結(jié)構(gòu)都需要通過make來創(chuàng)建
ch := make (chan int)
默認(rèn)情況下, 發(fā)收都需要對端準(zhǔn)備好了才行, 這樣的前提使得goroutine同步就不需要顯式的鎖處理,降低了復(fù)雜度,簡化的設(shè)計。
下面示例代碼, 對slice的值求和。 分布式的工作在兩個goroutine中。當(dāng)其兩個完成計算時,最終結(jié)果也計算出來了
*/
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
ex3
/*
Channels 就管道
導(dǎo)管通過第二個參數(shù),是可以指定其緩存長度的
ch := make(chan int, 100)
當(dāng)管道滿時, 發(fā)送會阻塞
當(dāng)管道空時, 接收會阻塞
修改下面的代碼,可以進(jìn)行測試一下
*/
package main
import (
"fmt"
"time"
)
// 例1、寫阻塞等待
func put_chan(ch chan int, n int) {
for i := 0 ; i < n; i++{
fmt.Println("put: ", i, time.Now().UTC())
ch <- i
}
close(ch)
}
func read_chan(ch chan int, quit chan int) {
for c := range ch{
time.Sleep(time.Duration(time.Second * 3))
fmt.Println(c, time.Now().UTC())
}
time.Sleep(time.Duration(time.Second * 3))
quit <- 1
}
func main() {
ch := make(chan int, 2)
quit := make(chan int)
go put_chan(ch, 10)
go read_chan(ch, quit)
fmt.Println("end", <- quit, time.Now().UTC())
}
//// 例2、讀阻塞等待
//func put_chan(ch chan int, n int) {
// for i := 0 ; i < n; i++{
// time.Sleep(time.Duration(time.Second * 3))
// ch <- i
// }
// time.Sleep(time.Duration(time.Second * 3))
// close(ch)
//}
//
//func read_chan(ch chan int, quit chan int) {
// for c := range ch{
// fmt.Println(c, time.Now())
// }
// quit <- 1
//}
//func main() {
// ch := make(chan int, 2)
// quit := make(chan int)
// go put_chan(ch, 2)
// go read_chan(ch, quit)
//
//
// fmt.Println("end", <- quit, time.Now())
//
//}
// 例3、測試中發(fā)現(xiàn),系統(tǒng)檢測會出現(xiàn)死鎖
//func main() {
// ch := make(chan int, 2)
// ch <- 1
// ch <- 2
// fmt.Println(<-ch)
// fmt.Println(<-ch)
// fmt.Println(<-ch)
// fmt.Println("end")
//
//}
ex4
/*
Channels Range & Close 范圍排列與關(guān)閉
發(fā)送者可以通過關(guān)閉通道來通知沒有更多數(shù)據(jù)需要發(fā)送了。
接收者可以檢測通道是否已經(jīng)關(guān)閉了,通過指定第二個參數(shù)來實現(xiàn),具體如下
v , ok := <- ch
當(dāng)ok為false, 則通道已經(jīng)關(guān)閉,沒有數(shù)據(jù)了。
或者可以使用循環(huán) for i := range c 來取數(shù)據(jù),至到通道關(guān)閉。
注意<慣例>:
1. 應(yīng)該只讓發(fā)送者來關(guān)閉通道。 絕對不要讓接收者來關(guān)閉。 在一個已經(jīng)關(guān)閉了的通道上發(fā)數(shù)據(jù)會引發(fā)panic
2. 通道,只在最終不要了, 需要終止的時候才來關(guān)閉之
*/
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
ex5
/*
Channels select 選擇查詢操作
選擇查詢語句, 讓當(dāng)前goroutine 等待多個通訊操作
當(dāng)沒有條件滿足時, select阻塞
當(dāng)有 條件滿足時, select執(zhí)行
當(dāng)有多條件滿足時, select隨機執(zhí)行滿足條件之一
*/
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x: // 寫
x, y = y, x+y
case <-quit: // 讀
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
ex6
/*
Channels select 選擇查詢操作
缺省選擇, 當(dāng)沒有case條件滿足時, 直接選擇默認(rèn)條件
*/
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}