go 語言並發機制 goroutine 初探

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

go 語言的一個很大的優勢就是可以方便地編寫並發程式。go 語言內建了 goroutine 機制。這是一種類似 coroutaine(協程) 的東西。但是又不完全相同。

比如這個例子:

package mainimport ("fmt""strconv")func main() {ch := make(chan int)task("A", ch)task("B", ch)fmt.Printf("begin\n")<-ch<-ch}func task(name string, ch chan int) {go func() {i := 1for {fmt.Printf("%s %d\n", name, i)i++}ch <- 1}()}

運行以後,發現會 A B 兩個 goroutine 會交替執行,並不像傳統的協程需要手動 schedule 。看起來很神奇。

稍稍改一下代碼,把

fmt.Printf("%s %d\n", name, i)

改成

print(name + " " + strconv.Itoa(i) + "\n")

再看看。神奇的效果消失了,只有 A 被運行。

那麼 fmt.Printf 和 print 有什麼差別,導致了這個結果呢?

大致翻了一下 go 的代碼,看出 go 語言在對 c lib 的封裝上用了個 cgo 的方式。而在通過 cgo 調用 c 庫的時候,會在調用時自動 schedule 切換走,在調用結束的時候再返回。這兩個結果的差異就在於,fmt.Printf 是通過 cgo 封裝的,而 print 則是原生實現的。所以在調用 fmt.Printf 的時候,就自動實現了調度。

傳統的 coroutaine 在訪問網路、資料庫等 io 操作時仍然會阻塞,失去並發能力,所以通常需要結合非同步 io 來實現。而現有的庫如果本身未提供非同步功能,就很難辦,往往需要重新實現。而且,即使有非同步 io 功能,也需要額外的開發,才能在表現上和以往順序程式相同的方式。

go 語言的這種實現方式很好的解決了這個問題,可以充分利用現有的大量 c 庫來封裝。

同時,也還是可以使用 runtime.Gosched() 來手動調度。在運算量大的情境下,也還是必要的。

在使用 print 的例子裡,如果使用 runtime.GOMAXPROCS(2),又可以重新並行起來。這時,兩個 goroutine 是在兩個獨立的線程中啟動並執行。這又是 goroutine 和協程的一個不同點。不過啟用多個線程並不見得能讓程式更快。因為跨線程的環境切換代價也是很大的。在上面那個簡單的例子裡,還會讓程式變得更慢。降低 環境切換開銷也是協程的一個優勢所在。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.