Goroutines
寫並發的代碼已經很困難了,寫並發訪問網路的代碼就更加困難了。問題在於傳統的線程不能很好得伸縮,而且線程一旦運行起來,就會很難去控制。Go語言項目組著手解決這個問題,於是乎goroutine就誕生了。
本質上, goroutines是個輕量級的並發機制,通過使用一種稱為channels的構建來進行線程間互動。它們都非常便於使用:
package main import "fmt" func wait() { //wait around with a forever loop for { }} func main() { go wait() fmt.Println("We didn't wait because it was called as a goroutine!")}
在上面的代碼中,wait方法是一個死迴圈,但是我們通過go wait()的方式來調用,而非直接的通過wait()來調用。這是告訴Go我們希望以一個goroutine的方式來調用,同時非同步運行。既然這個迴圈是在後台啟動並執行,那樣運行這個程式就不會因為死迴圈而阻塞。
這麼說,Go從語言本身支援並發。也就是,Go語言中有並發基元(primitives)。這樣意義何在呢?僅僅因為不是由某個庫或者模組來實現並發,這好像不是什麼了不起的舉措啊。但是,實際上goroutine從根本上與線程不同。goroutine更加輕量化。還記得在伺服器中,我們不該為每個用戶端建立一個線程吧?但是,使用goroutine,情況就不同了:
package main import ( "fmt" "net") //notice that in the arguments, the name of//the variable comes first, then comes the//type of the variable, just like in "var"//declarationsfunc manageClient(conn net.Conn) { conn.Write([]byte("Hi!")) conn.Close() //do something with the client} func main() { //we are creating a server her that listens //on port 1337. Notice that, similar to Ruby, //a method can have two return values (although //in Ruby, this would be an array instead) listener, err := net.Listen("tcp", ":1337") for { //accept a connection connection, _ := listener.Accept() go manageClient(connection) }}
噢,等會!這些代碼似有那麼一小點複雜啊,雖然想法是很簡單。好吧,讓我們一步一步慢慢來 |