Go 语言中的并发可以用两种方式实现:
- 第一种方式,支持顺序通信进程(communicating sequential processes),简称 CSP。CSP是一种现代的并发编程模型,在这种编程模型中值会在不同的运行实例(goroutine)中传递,尽管大多数情况下仍然是被限制在单一实例中。
- 第二种实现方式就是更为传统的并发模型:多线程共享内存。
示例1
主 goroutine和后台goroutine
func main() { go spinner(100 * time.Millisecond) const n = 45 fibN := fib(n) // slow 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) }
示例2
下面的例子是顺序执行的时钟服务器,它会每隔一秒钟将当前时间写到客户端
package mainimport ( "log" "net" "time" "io" )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) // e.g., connection aborted continue } handleConn(conn) // handle one connection at a time } }func handleConn(c net.Conn) { defer c.Close() for { _, err := io.WriteString(c, time.Now().Format("15:04:05\n")) if err != nil { return // e.g., client disconnected } time.Sleep(1 * time.Second) } }
分析:
net.Listen函数创建了一个net.Listener的对象,这个对象会监听一个网络端口上到来的连接,在这个例子里我们用的是TCP的localhost:8000端口。listener对象的Accept方法会直接阻塞,直到一个新的连接被创建,然后会返回一个net.Conn对象来表示这个连接。
可以使用 netcat命令连接这个服务。
文章图片
或者使用 net.Dial() 来连接这个服务
// This is a read-only TCP client. package mainimport ( "io" "log" "net" "os" )func main() { conn, err := net.Dial("tcp", "localhost:8000") if err != nil { log.Fatal(err) } defer conn.Close() mustCopy(os.Stdout, conn) }func mustCopy(dst io.Writer, src io.Reader) { if _, err := io.Copy(dst, src); err != nil { log.Fatal(err) } }
net.Dial() 拨号,返回一个连接。从连接中获取数据打印到输出流。
【Goroutines】
并发分析:
上面的服务端同时只能处理一个客户端连接,客户端必须等服务端完成工作才执行。为了支持并发,在handleConn函数调用的地方增加go关键字,让每一次handleConn的调用都进入一个独立的goroutine。
示例3
并发的 echo服务。在单个连接中建立多个 goroutine
转载于:https://www.cnblogs.com/lemos/p/6872745.html