golang实现异步并发sokect
package main import ( "fmt" "net" "os" "time" ) const ( MAX_CONN_NUM = 5 ) //echo server Goroutine func EchoFunc(conn net.Conn) { defer conn.Close() buf := make([]byte, 1024) for { _, err := conn.Read(buf) if err != nil { //println("Error reading:", err.Error()) return } //send reply _, err = conn.Write(buf) if err != nil { //println("Error send reply:", err.Error()) return } } } //initial listener and run func main() { listener, err := net.Listen("tcp", "0.0.0.0:8088") if err != nil { fmt.Println("error listening:", err.Error()) os.Exit(1) } defer listener.Close() fmt.Printf("running ...\n") var cur_conn_num int = 0 conn_chan := make(chan net.Conn) ch_conn_change := make(chan int) go func() { for conn_change := range ch_conn_change { cur_conn_num += conn_change } }() go func() { for _ = range time.Tick(1e8) { fmt.Printf("cur conn num: %f\n", cur_conn_num) } }() for i := 0; i < MAX_CONN_NUM; i++ { go func() { for conn := range conn_chan { ch_conn_change <- 1 EchoFunc(conn) ch_conn_change <- -1 } }() } for { conn, err := listener.Accept() if err != nil { println("Error accept:", err.Error()) return } conn_chan <- conn } }
再看这段代码使用传统思维实行方式:
// //A echo server with max-connections limit and interval connection show // package main import ( "fmt" "net" "os" "time" ) const ( MAX_CONN_NUM = 5 ) //echo server Goroutine func EchoFunc(conn net.Conn, conn_close_flag chan int) { defer conn.Close() defer func() { conn_close_flag <- -1 }() buf := make([]byte, 1024) for { _, err := conn.Read(buf) if err != nil { //println("Error reading:", err.Error()) return } //send reply _, err = conn.Write(buf) if err != nil { //println("Error send reply:", err.Error()) return } } } //initial listener and run func main() { listener, err := net.Listen("tcp", "0.0.0.0:8088") if err != nil { println("error listening:", err.Error()) os.Exit(1) } defer listener.Close() fmt.Printf("running ...\n") var cur_conn_num float64 = 0 ch_conn_change := make(chan int, MAX_CONN_NUM) tick := time.Tick(1e8) for { //read all close flags berfor accept new connection //TODO: better code to handle batch close? readmore := 1 for readmore > 0 { select { case conn_change := <-ch_conn_change: cur_conn_num = cur_conn_num + float64(conn_change) default: readmore = 0 } } //FIXME: tick block by listener.Accept() select { case <-tick: fmt.Printf("cur conn num: %f\n", cur_conn_num) default: } if cur_conn_num >= MAX_CONN_NUM { //reach MAX_CONN_NUM, waiting for exist connection close time.Sleep(time.Second) } else { //accept new connetion conn, err := listener.Accept() if err != nil { println("Error accept:", err.Error()) return } cur_conn_num++ go EchoFunc(conn, ch_conn_change) } } }
这个案例中,golang通过多个goroutine + channel堵塞做到传统的顺序执行模式。
代码来自google group的讨论:https://groups.google.com/forum/#!topic/golang-china/q4pFH-AGnfs
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。