Chapter 8 Goroutines and Channels
Go enable two styles of concurrent programming. This chapter presents coroutines and channels, which support communicating sequential processes or CSP, a model of concurrency in which values are passed between independent activities (goroutines) but variables are for the the most part confined to a single activity. Chapter 9 covers some aspects of the more traditional model of shared memory multithreading, which will be familiar if you've used threads in other mainstream languages. Chapter 9 also points out some important hazards and pitfalls of concurrent programming that we won't delve into in this chapter.
goroutine 兩種模式,一種用於兩個 goroutine 之間的交流,variables 被限定在一個單獨的 activities。
另一種類似於其他主流語言的多線程,特點是 shared memory multithreading。
8.1 Goroutines
In Go, each concurrently executing activity is called a goroutine.
golang中,每個並發執行的 activity 被稱為 goroutine。
If you have used operating system threads or threads in other languages, then you can assume for now that a goroutine is similar to a thread, and you'll be able to write correct programs. The differences between threads and goroutines are essentially quantitative, not qualitative, and will be described in Section 9.8.
threads 與 goroutines 的區別是定量的,而非定性的。在9.8中講會進行進一步的解釋。
When a program starts, its only goroutine is the one that calls the main function, so we call it the main goroutine. New goroutines are created by the go statement. Syntactically, a go statement is an ordinary function or method call prefixed by the keyword go. A go statement causes the function to be called in a newly created goroutine. The go statement itself completes immediately:
當一個程式啟動後,程式唯一的main function 就是 main goroutine。
package mainimport ( "time" "fmt")func main() { go spinner(5 * time.Millisecond) const n = 45 fibN := fib(n) fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)}func spinner(delay time.Duration) { for { for _, r := range `-\|/` { fmt.Printf("\r%c", r) time.Sleep(delay) } }}func fib(x int) int { if x < 2 { return x } return fib(x - 1) + fib(x - 2)}
程式裡的 /r 表示斷行符號
Other than by returning from main or exiting the program, there is no programmatic way for one goroutine to stop another, but as we will see later, there are ways to communicate with a goroutine to request that it stop itself.
除了從 main 函數返回 或者 退出當前的程式,沒有程式上的辦法能讓一個 goroutine 來停止另一個 goroutine,但是有辦法讓一個 goroutine 向另一個 goroutine 發送訊息,讓他自己停止下來。
8.2 Example: Concurrent Clock Server
一個時鐘例子
伺服器
package mainimport ( "net" "log" "io" "time")func main() { listener, err := net.Listen("tcp", "localhost:8000") if err != nil { log.Fatal(err) } for { conn, err := listener.Accept() if err != nil { log.Print(err) continue } handleConn(conn) }}func handleConn(c net.Conn) { defer c.Close() for { _, err := io.WriteString(c, time.Now().Format("15:04:05\n")) if err != nil { return } time.Sleep(1 * time.Second) }}
重要的是三步:
- listener, err := net.Listen("tcp", "localhost:8000")
- conn, err := listener.Accept()
- _, err := io.WriteString(c, time.Now().Format("15:04:05\n"))
注釋:採用的時間必須是 2016/1/2 15:04:05 (123456) 一月二號 三點四分五秒
https://segmentfault.com/q/1010000010976398/a-1020000010982052
在用戶端採用 nc 命令串連
nc localhost 8000
用戶端
package mainimport ( "net" "log" "io" "os")func main() { conn, err := net.Dial("tcp", "localhost:8000") if err != nil { log.Fatal(err) } defer conn.Close() _, err1 := io.Copy(os.Stdout, conn) if err != nil { log.Fatal(err1) }}