go 程(goroutine)是由 go 執行時管理的輕量級執行緒。
go f(x, y, z)
會啟動乙個新的 go 程並執行
f(x, y, z)
f
,x
,y
和z
的求值發生在當前的 go 程中,而f
的執行發生在新的 go 程中。
go 程在相同的位址空間中執行,因此在訪問共享的記憶體時必須進行同步。sync
package main
import
("fmt"
"time"
)func
say(s string)}
func
main()
結果:
world
hello
hello
world
world
hello
hello
world
world
hello
通道是帶有型別的管道,你可以通過它用通道操作符<-
來傳送或者接收值。
ch <- v // 將 v 傳送至通道 ch。
v := <-ch // 從 ch 接收值並賦予 v。
(「箭頭」就是資料流的方向。)
和對映與切片一樣,通道在使用前必須建立:
ch := make(chan int)
預設情況下,傳送和接收操作在另一端準備好之前都會阻塞。這使得 go 程可以在沒有顯式的鎖或競態變數的情況下進行同步。
以下示例對切片中的數進行求和,將任務分配給兩個 go 程。一旦兩個 go 程完成了它們的計算,它就能算出最終的結果。
package main
import
"fmt"
func
sum(s [
]int
, c chan
int)
c <- sum
}func
main()
c :=
make
(chan
int)
gosum
(s[:
len(s)/2
], c)
gosum
(s[len
(s)/2:
], c)
x, y :=
<-c,
<-c
fmt.
println
(x, y, x+y)
}
結果:
-5 17 12
通道可以是 帶緩衝的。將緩衝長度作為第二個引數提供給make
來初始化乙個帶緩衝的通道:
ch := make(chan int, 100)
僅當通道的緩衝區填滿後,向其傳送資料時才會阻塞。當緩衝區為空時,接受方會阻塞。
修改示例填滿緩衝區,然後看看會發生什麼。
package main
import
"fmt"
func
main()
結果:
1
2
傳送者可通過close
關閉乙個通道來表示沒有需要傳送的值了。接收者可以通過為接收表示式分配第二個引數來測試通道是否被關閉:若沒有值可以接收且通道已被關閉,那麼在執行完
v, ok := <-ch
之後ok
會被設定為false
。
迴圈for i := range c
會不斷從通道接收值,直到它被關閉。
注意: 只有傳送者才能關閉通道,而接收者不能。向乙個已經關閉的通道傳送資料會引發程式恐慌(panic)。
還要注意: 通道與檔案不同,通常情況下無需關閉它們。只有在必須告訴接收者不再有需要傳送的值時才有必要關閉,例如終止乙個range
迴圈。
package main
import
"fmt"
func
fibonacci
(n int
, c chan
int)
close
(c)}
func
main()
}
結果:
011
2358
1321
34
select
語句使乙個 go 程可以等待多個通訊操作。
select
會阻塞到某個分支可以繼續執行為止,這時就會執行該分支。當多個分支都準備好時會隨機選擇乙個執行。
package main
import
"fmt"
func
fibonacci
(c, quit chan
int)}}
func
main()
quit <-0}
()fibonacci
(c, quit)
}
結果:
011
2358
1321
34quit
當select
中的其它分支都沒有準備好時,default
分支就會執行。
為了在嘗試傳送或者接收時不發生阻塞,可使用default
分支:
select
package main
import
("fmt"
"time"
)func
main()
}}
結果:
.
.tick.
. .tick.
. .tick.
. .tick.
. .tick.
boom!
我們已經看到通道非常適合在各個 go 程間進行通訊。
但是如果我們並不需要通訊呢?比如說,若我們只是想保證每次只有乙個 go 程能夠訪問乙個共享的變數,從而避免衝突?
這裡涉及的概念叫做 互斥(mutualexclusion)* ,我們通常使用 互斥鎖(mutex) 這一資料結構來提供這種機制。
go 標準庫中提供了sync.mutex
互斥鎖型別及其兩個方法:
我們可以通過在**前呼叫lock
方法,在**後呼叫unlock
方法來保證一段**的互斥執行。參見inc
方法。
我們也可以用defer
語句來保證互斥鎖一定會被解鎖。參見value
方法。
package main
import
("fmt"
"sync"
"time"
)//safecounter 的併發使用是安全的
type safecounter struct
//inc增加給定key的計數器的值
func
(c *safecounter)
inc(key string
)//value返回給定key的計數器的當前值
func
(c *safecounter)
value
(key string
)int
func
main()
for i :=
0; i <
1000
; i++
time.
sleep
(time.second)
fmt.
println
(c.value
("somekey"))
}
結果:
1000
Go語言從入門到高階
3.條件和迴圈 4.函式 5.陣列和指標 6.結構體和切片 7.集合 8.併發 9.通道 練習package main import fmt func main package main var a 菜鳥教程 var b string runoob.com var c bool var x,y in...
Go語言從入門到放棄 變數
使用關鍵字var var v1 int 整型 var v2 string 字串 var v3 10 int 陣列 var v4 int 陣列切片 var v5 struct var v6 int 指標 var v7 map string map,key為string型別,value為int型別還有一...
go語言 從入門到棄療
小白第一次寫部落格,還有點小緊張 先說說背景吧,去年年底我參加了學院的乙個區塊鏈專案組,花了整整乙個寒假的時間去熟悉hyperledger composer 的實驗,總共六個官方教程,如果感興趣可以看一看 開學以後我們便要開始學習區塊鏈的底層 了,沒錯就是這個 不過在這之前,乙個問題擺在我們面前,區...