golang非同期同時sokectの実現


golang+epollの例を検索して、次のコードを得て、golangのプログラミング思考が本当に並列プログラミングをしたと感じます.
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 ...
") 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
", 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 ...
") 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
", 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グループの議論から来ています.https://groups.google.com/forum/#!topic/golang-china/q4pFH-AGnfs