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。
- f()
- go f()
package main
import (
"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 main
import (
"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 main
import (
"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)
}
}
有疑问加站长微信联系(非本文作者)