go語句初探

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。go語句和通道類型是Go語言的並發編程理念的最終體現。相比之下,go語句在用法上要比通道簡單很多。與defer語句相同,go語句也可以攜帶一條運算式語句。注意,go語句的執行會很快結束,並不會對當前流程的進行造成阻塞或明顯的延遲。一個簡單的樣本如下:


go fmt.Println("Go!")
    可以看到,go語句僅由一個關鍵字go和一條運算式語句構成。同樣的,go語句的執行與其攜帶的運算式語句的執行在時間上沒有必然聯絡。這裡能夠確定的僅僅是後者會在前者完成之後發生。在go語句被執行時,其攜帶的函數(也被稱為go函數)以及要傳給它的若干參數(如果有的話)會被封裝成一個實體(即Goroutine),並被放入到相應的待運行隊列中。Go語言的運行時系統會適時的從隊列中取出待啟動並執行Goroutine並執行相應的函數叫用作業。注意,對傳遞給這裡的函數的那些參數的求值會在go語句被執行時進行。這一點也是與defer語句類似的。
  
    正是由於go函數的執行時間的不確定性,所以Go語言提供了很多方法來協助協調它們的執行。其中最簡單粗暴的方法就是調用time.Sleep函數。請看下面的樣本:


package main


import (
    "fmt"
)


func main() {
    go fmt.Println("Go!")
}  
    這樣一個命令源碼檔案被運行時,標準輸出上不會有任何內容出現。因為還沒等Go語言運行時系統調度那個go函數執行,主函數main就已經執行完畢了。函數main的執行完畢意味著整個程式的執行的結束。因此,這個go函數根本就沒有執行的機會。
  
  但是,在上述go語句的後面添加一條對time.Sleep函數的調用語句之後情況就會不同了:


package main


import (
    "fmt"
    "time"
)


func main() {
    go fmt.Println("Go!")
    time.Sleep(100 * time.Millisecond)
}
    語句time.Sleep(100 * time.Millisecond)會把main函數的執行結束時間向後延遲100毫秒。100毫秒雖短暫,但足夠go函數被調度執行的了。上述命令源碼檔案在被運行時會如我們所願地在標準輸出上列印出Go!。


  
    另一個比較紳士的做法是在main函數的最後調用runtime.Gosched函數。相應的程式版本如下:


package main


import (
    "fmt"
    "runtime"
)


func main() {
    go fmt.Println("Go!")
    runtime.Gosched()
}
   runtime.Gosched函數的作用是讓當前正在啟動並執行Goroutine(這裡是運行main函數的那個Goroutine)暫時“休息”一下,而讓Go運行時系統轉去運行其它的Goroutine(這裡是與go fmt.Println("Go!")對應並會封裝fmt.Println("Go!")的那個Goroutine)。如此一來,就更加精細地控制了對幾個Goroutine的啟動並執行調度。
  
    當然,還有其它方法可以滿足上述需求。並且,如果需要去左右更多的Goroutine的運行時機的話,下面這種方法也許更合適一些。請看代碼:


package main


import (
    "fmt"
    "sync"
)


func main() {
    var wg sync.WaitGroup
    wg.Add(3)
    go func() {
        fmt.Println("Go!")
        wg.Done()
    }()
    go func() {
        fmt.Println("Go!")
        wg.Done()
    }()
    go func() {
        fmt.Println("Go!")
        wg.Done()
    }()
    wg.Wait()
}

    sync.WaitGroup類型有三個方法可用——Add、Done和Wait。Add會使其所屬值的一個內建整數得到相應增加,Done會使那個整數減1,而Wait方法會使當前Goroutine(這裡是運行main函數的那個Goroutine)阻塞直到那個整數為0。這下你應該明白上面這個樣本所採用的方法了。在main函數中啟用了三個Goroutine來封裝三個go函數。每個匿名函數的最後都調用了wg.Done方法,並以此表達當前的go函數會立即執行結束的情況。當這三個go函數都調用過wg.Done函數之後,處於main函數最後的那條wg.Wait()語句的阻塞作用將會消失,main函數的執行將立即結束。


package mainimport (    "fmt")func main() {    ch1 := make(chan int, 1)    ch2 := make(chan int, 1)    ch3 := make(chan int, 3)    go func() {        fmt.Println("1")        ch1 <- 1    }()    go func() {        <-ch1        fmt.Println("2")        ch2 <- 2    }()    go func() {        <-ch2        fmt.Println("3")        ch3 <- 3    }()    <-ch3}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.