一、併發
併發程式設計表現為程式有若干個自主的活動單元組成,在今天的網際網路中,一個web伺服器可能一次處理上千個請求,而平板電腦和手機在渲染使用者介面的同時,後端還同步進行著計算和處理網路請求等。
在go語言中每一個併發執行的活動稱之為goroutine,而在我們最常見的main函式中其實也是一個goroutine(主goroutine),在此之前,我們所見的介紹語法或者程式都是順序執行的,但是在併發程式設計的領域裡,如果從順序程式設計獲取的直覺可能讓我們加倍迷茫。
在此我們需要理解什麼是併發:
百科:當有多個執行緒在操作時,如果系統只有一個CPU,則它根本不可能真正同時進行一個以上的執行緒,它只能把CPU執行時間劃分成若干個時間段,再將時間 段分配給各個執行緒執行,在一個時間段的執行緒程式碼執行時,其它執行緒處於掛起狀。.這種方式我們稱之為併發(Concurrent)。
(這個是普通函式的執行模式,main將其控制權交給呼叫的函式,最後在返回給main)
我的理解:舉個例子,我一邊在上網課,一邊在做筆記,我在做筆記的時候需要將網課暫停,等我的筆記做完後又繼續看網課,這兩件事就可以看作是一個併發的過程。
(協程則是:main和建立的goroutine是相互作用的,相互給予控制權,就像兩個人,各做各的事,並且他們也相互通訊)
二、go關鍵字
當一個程式啟動時,只有一個goroutine來呼叫main
,稱他為主goroutine,新的goroutine透過go
關鍵字來進行建立,看下面例子:
func main() {
for i := 0; i < 3; i++ {
//使用go關鍵字建立goroutine
//匿名函式
go func() {
for j := 3; j >= 0; j-- {
fmt.Println("gorouting", j)
}
}()
fmt.Println("gorouting mian:", i)
//控制程式執行時間
time.Sleep(time.Microsecond)
}
}
當然,也可以將匿名函式拿出來:
package main
import (
"fmt"
"time")
func doWorker() {
for j := 3; j >= 0; j-- {
fmt.Println("gorouting", j)
}
}
func main() {
for i := 0; i < 3; i++ {
//使用go關鍵字建立goroutine
go doWroker()
fmt.Println("gorouting mian:", i)
//控制程式執行時間
time.Sleep(time.Microsecond)
}
}
先來看看列印結果:
gorouting mian: 0
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 1
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 2
gorouting 3
gorouting 2
gorouting 1
gorouting 0
第二遍執行:
gorouting mian: 0
gorouting mian: 1
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 2
gorouting 3
gorouting 2
gorouting 1
gorouting 0
程式解釋:其實可以看出,每一遍的執行結果都是不一樣的,當程式加入第一個for , i=0時,執行到關鍵字go
時,新的goroutine就建立了,但是程式不會立即執行新的goroutine,它會進行執行main中其餘的程式碼,在我們的這個例子中,第一遍執行,時就是這個結果,第二遍執行時也是同樣的。
func main(){
var a[10] int
for i := 0; i < 10;i++{
//使用go關鍵字建立goroutine
//匿名函式
go func(i int){
for{
a[i]++
}
}(i)
}
time.Sleep(time.Microsecond)
fmt.Println(a)
}
列印結果:
[39904 0 0 9122 0 7123 0 0 0 0]
程式解釋:在for迴圈中一共建立了10個goroutine,有的goroutine執行了,有的還處於等待狀態,但是我們給主goroutine的時間不多,所以有一些還來不及執行就被主goroutine殺掉了,這樣我們就能理解列印結果了。
三、goroutine切換點(可能)
goroutine可能切換:
- I/O、select
- channel
- 等待鎖
- 函式呼叫(有時)
- runtime.Gosched
本作品採用《CC 協議》,轉載必須註明作者和本文連結