我以为我找到了一种简单的方法来立即返回http响应,然后在后台进行一些工作而不会阻塞。但是,这不起作用。
func MyHandler(w http.ResponseWriter, r *http.Request) {
//handle form values
go doSomeBackgroundWork() // this will take 2 or 3 seconds
w.WriteHeader(http.StatusOK)
}
它第一次工作 - 立即返回响应并开始后台工作。但是,任何进一步的请求都会挂起,直到后台goroutine完成。有没有更好的方法,这不涉及设置消息队列和单独的后台进程。
答案 0 :(得分:8)
将多路复用goroutine转移到由GOMAXPROCS
环境设置确定的可用线程上。因此,如果将此值设置为1,则单个goroutine可以占用单个线程Go可用,直到它将控制权返回到Go运行时。很可能doSomeBackgroundWork
一直在单个线程上占用,这阻止了http处理程序的调度。
有很多方法可以解决这个问题。
首先,作为使用goroutines时的一般规则,您应该将GOMAXPROCS
设置为系统具有的CPU数量或更大的CPU数量。
其次,您可以通过执行以下任一操作来控制goroutine:
runtime.Gosched()
ch <- foo
foo := <-ch
select { ... }
mutex.Lock()
mutex.Unlock()
所有这些都将回退到Go运行时调度程序,为其他goroutine提供工作机会。
答案 1 :(得分:6)
我知道这个问题是4年前发布的,但我希望有人能发现这个问题很有用。
这是一种方法
有一些叫做工作池https://gobyexample.com/worker-pools使用go例程和通道
但是在下面的代码中我将它改编为处理程序。 (为简单起见,我忽略了错误,并且我将作业用作全局变量)
package main
import (
"fmt"
"net/http"
"time"
)
var jobs chan int
func worker(jobs <-chan int) {
fmt.Println("Register the worker")
for i := range jobs {
fmt.Println("worker processing job", i)
time.Sleep(time.Second * 5)
}
}
func handler(w http.ResponseWriter, r *http.Request) {
jobs <- 1
fmt.Fprintln(w, "hello world")
}
func main() {
jobs = make(chan int, 100)
go worker(jobs)
http.HandleFunc("/request", handler)
http.ListenAndServe(":9090", nil)
}
解释:
主要()强>
<强>工人()强>
<强>处理程序()强>
这太棒了Go!