一,并发
package main import ( "bufio" "fmt" "math" "os" ) const result = "Polar radius=%.02f θ=%.02f° → Cartesian x=%.02f y=%.02f " var prompt = "Enter a radius and an angle (in degrees), e.g., 12.5 90, " + "or %s to quit." type polar struct { radius float64 tt float64 } type cartesian struct { x float64 y float64 } func init() { prompt = fmt.Sprintf(prompt, "Ctrl+D") } func main() { questions := make(chan polar) defer close(questions) answers := CreateSolver(questions) defer close(answers) interact(questions, answers) } func CreateSolver(questions chan polar) chan cartesian { answers := make(chan cartesian) go func() { for { polarCoord := <-questions tt := polarCoord.tt * math.Pi / 180 x := polarCoord.radius * math.Cos(tt) y := polarCoord.radius * math.Sin(tt) answers <- cartesian{x, y} } }() return answers } func interact(questions chan polar, answers chan cartesian) { reader := bufio.NewReader(os.Stdin) fmt.Println(prompt) for { fmt.Printf("radius and angle :") line, err := reader.ReadString(' ') if err != nil { break } var radius, tt float64 if _, err := fmt.Sscanf(line, "%f %f", &radius, &tt); err != nil { fmt.Println(os.Stderr, "invalid input") continue } questions <- polar{radius, tt} coord := <-answers fmt.Printf(result, radius, tt, coord.x, coord.y) } fmt.Println() }
main函数做了几个事情
1.创建questions通道
2.创建solver通道,启动计算协程
3.进行主循环(使用了没有条件的for)
这个程序使用了go的协程,协程的创建方法:go 函数。协程要和主进程通信,所以创建了两个通道,一个通道是主进程写入数据,协程来读取,一个通道协程创建,主进程读取。
二,协程。
goroutine是程序中与其他goroutine完全相互独立而并发执行的函数活着方法调用。每一个go程序都至少有一个goroutine,即会执行main包中main函数的主goroutine。goroutine非常像轻量级的线程或者协程,他们可以批量的创建。所有的goroutine享有相同的地址空间,同时go语言提供了锁原语来保证数据能够安全的跨goroutine共享。然而go语言推荐的并发编程方式是通信,而非数据共享。
关于通道,如果给定了一个缓冲区的容量,那么通信就是异步的,只要缓冲区有未使用的空间用于发送数据,或还包含可以接收的数据,那么其通信酒会无阻塞的进行。如果是没有缓冲区的通道,或者通道满了,那么就将变成同步的通信。
goroutine接收数据的时候,可以使用select同时监听多个通道,任意一个通道有数据,就会激活对应通道的处理。