Handle 1 million concurrent connections with 50 lines of code in Go

Hi forum,

I am going through this page: 单机百万并发,golang 50行代码 - Go语言中文网 - Golang中文社区 , It claims that the 50 lines of code in Go handles 1 million concurrent connections from network clients on 1 single server machine with a 4-Core CPU and 16G memory.

Does the package net already utilize IO Multiplexing internally, like epoll (epoll_create, epoll_ctl, epoll_wait)? So I can just use package net and gain the epoll ability automatically without calling epoll apis manually in Go?

Thanks

Server:

package main

import (
    "fmt"
    "net"
    "os"
    "time"
)

var array []byte = make([]byte, 10)

func checkError(err error, info string) (res bool) {

    if err != nil {
        fmt.Println(info + "  " + err.Error())
        return false
    }
    return true
}

func Handler(conn net.Conn) {
    for {
        _, err := conn.Write(array)
        if err != nil {
            return
        }
        time.Sleep(10 * time.Second)
    }
}

func main() {

    for i := 0; i < 10; i += 1 {
        array[i] = 'a'
    }

    service := ":8888"
    tcpAddr, _ := net.ResolveTCPAddr("tcp4", service)
    l, _ := net.ListenTCP("tcp", tcpAddr)

    for {
        conn, err := l.Accept()
        if err != nil {
            fmt.Printf("accept error, err=%s\n", err.Error())
            os.Exit(1)
        }
        go Handler(conn)
    }

}

Client:

package main

import (
    "flag"
    "fmt"
    "net"
    "os"
    "time"
)

var RemoteAddr *string
var ConcurNum *int
var LocalAddr *string

func init() {
    RemoteAddr = flag.String("remote-ip", "127.0.0.1", "ip addr of remote server")
    ConcurNum = flag.Int("concurrent-num", 100, "concurrent number of client")
    LocalAddr = flag.String("local-ip", "0.0.0.0", "ip addr of remote server")
}

func consume() {

    laddr := &net.TCPAddr{IP: net.ParseIP(*LocalAddr)}

    var dialer net.Dialer
    dialer.LocalAddr = laddr

    conn, err := dialer.Dial("tcp", *RemoteAddr+":8888")
    if err != nil {
        fmt.Println("dial failed:", err)
        os.Exit(1)
    }
    defer conn.Close()

    buffer := make([]byte, 512)

    for {
        _, err2 := conn.Read(buffer)
        if err2 != nil {
            fmt.Println("Read failed:", err2)
            return
        }

        //  fmt.Println("count:", n, "msg:", string(buffer))

    }

}

func main() {
    flag.Parse()
    for i := 0; i < *ConcurNum; i++ {
        go consume()
    }
    time.Sleep(3600 * time.Second)
}

Hi @ljh,

Yes, there is no need for epoll calls. It is not the net package, but rather the Go scheduler that does the polling for you. In a nutshell, whenever a goroutine does net I/O, the scheduler hands the goroutine over to the netpoller and lets other goroutines run.

I found this article that provides some more details about network I/O and the netpoller.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.