how to use multiple processes with http

huangapple go评论79阅读模式
英文:

how to use multiple processes with http

问题

如何利用所有的CPU并为每个CPU生成一个HTTP进程?

获取CPU数量

numCPU := runtime.NumCPU()

启动HTTP

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
英文:

How to make use of all CPUs and spawn a http process for each CPU?

Get num of CPUs

numCPU := runtime.NumCPU()

Start http

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

答案1

得分: 6

如果你的目标只是让你的“请求处理代码”在所有CPU核心上运行,net/http已经会为每个连接启动一个goroutine(一种类似线程的东西,具有Go特定的实现),并且Go默认会安排NumCPU个操作系统线程运行,以便将goroutine分布在所有可用的CPU核心上。

Accept循环在一个goroutine中运行,但实际的请求解析和响应生成工作会在每个连接中的一个goroutine中运行。

英文:

If your goal is just to have your request-processing code run on all CPU cores, net/http already starts a goroutine (a vaguely thread-like thing with a Go-specific implementation) per connection, and Go arranges for NumCPU OS threads to run by default so that goroutines can be spread across all available CPU cores.

The Accept loop runs in a single goroutine, but the actual work of parsing requests and generating responses runs in one per connection.

答案2

得分: 1

你可以自己编写一个包装器来实现这个功能:

// 从 http://golang.org/src/pkg/net/http/server.go#L1942 复制
type tcpKeepAliveListener struct {
    *net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
    tc, err := ln.AcceptTCP()
    if err != nil {
        return
    }
    tc.SetKeepAlive(true)
    tc.SetKeepAlivePeriod(3 * time.Minute)
    return tc, nil
}

func ListenAndServe(addr string, num int) error {
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    var wg sync.WaitGroup
    for i := 0; i < num; i++ {
        wg.Add(1)
        go func(i int) {
            log.Println("listener number", i)
            log.Println(http.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}, nil))

            wg.Done()
        }(i)
    }
    wg.Wait()
    return nil
}

func main() {
    num := runtime.NumCPU()
    runtime.GOMAXPROCS(num) // 使得 goroutine 监听器可以在多个线程上运行
    log.Println(ListenAndServe(":9020", num))
}

或者如果你使用的是足够新的 Linux 内核你可以使用来自 http://comments.gmane.org/gmane.comp.lang.go.general/121122 的补丁,实际上生成多个进程。
英文:

You can't nativly, you have to write your own wrapper:

// copied from http://golang.org/src/pkg/net/http/server.go#L1942
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}

func ListenAndServe(addr string, num int) error {
	if addr == &quot;&quot; {
		addr = &quot;:http&quot;
	}
	ln, err := net.Listen(&quot;tcp&quot;, addr)
	if err != nil {
		return err
	}
	var wg sync.WaitGroup
	for i := 0; i &lt; num; i++ {
		wg.Add(1)
		go func(i int) {
			log.Println(&quot;listener number&quot;, i)
			log.Println(http.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}, nil))

			wg.Done()
		}(i)
	}
	wg.Wait()
	return nil
}

func main() {
	num := runtime.NumCPU()
	runtime.GOMAXPROCS(num) //so the goroutine listeners would try to run on multiple threads
	log.Println(ListenAndServe(&quot;:9020&quot;, num))
}

Or if you use a recent enough Linux Kernel you can use the patch from http://comments.gmane.org/gmane.comp.lang.go.general/121122 and actually spawn multiple processes.

huangapple
  • 本文由 发表于 2014年9月29日 01:20:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/26087507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定