我正在尝试构建一个简单的Golang / Appengine应用程序,该应用程序使用通道来处理每个http请求。原因是我希望每个请求执行合理的大内存计算,并且以线程安全的方式执行每个请求非常重要(即并发请求的计算不会混合)。
基本上我需要一个同步队列,它一次只处理一个请求,并且通道看起来很自然。
Is it possible to use Go's buffered channel as a thread-safe queue?
然而,我无法让我的简单hello世界示例工作。它似乎在'go process(w,cr)'线上失败了;我从服务器得到200响应,但没有竞争对手。如果我从这一行消除'go',那么工作正常,但我猜我没有正确地调用频道。
有人指出我哪里出错了?
谢谢!
// curl -X POST "http://localhost:8080/add" -d "{\"A\":1, \"B\":2}"
package hello
import (
"encoding/json"
"net/http"
)
type MyStruct struct {
A, B, Total int64
}
func (s *MyStruct) add() {
s.Total = s.A + s.B
}
func process(w http.ResponseWriter, cr chan *http.Request) {
r := <- cr
var s MyStruct
json.NewDecoder(r.Body).Decode(&s)
s.add()
json.NewEncoder(w).Encode(s)
}
func handler(w http.ResponseWriter, r *http.Request) {
cr := make(chan *http.Request, 1)
cr <- r
go process(w, cr) // doesn't work; no response :-(
// process(w, cr) // works, but blank response :-(
}
func init() {
http.HandleFunc("/add", handler)
}
答案 0 :(得分:3)
不确定这是否是正确的设计,但我怀疑问题在于你开始第二个例行程序,第一个例程继续并完成连接等。
要停止此操作,您可以使用等待组(http://golang.org/pkg/sync/#WaitGroup)使第一个例程等待。
这样就停止了为什么你要把它放到一个线程中的整个推理(因此我认为你有一个设计问题)。
以下是一些未经测试的代码,它们应该起作用或至少在正确的方向上提供帮助。
package main
import (
"encoding/json"
"net/http"
"sync"
)
type MyStruct struct {
A, B, Total int64
}
func (s *MyStruct) add() {
s.Total = s.A + s.B
}
func process(w http.ResponseWriter, cr chan *http.Request) {
r := <- cr
var s MyStruct
json.NewDecoder(r.Body).Decode(&s)
s.add()
json.NewEncoder(w).Encode(s)
}
func handler(w http.ResponseWriter, r *http.Request) {
cr := make(chan *http.Request, 1)
cr <- r
var pleasewait sync.WaitGroup
pleasewait.Add(1)
go func() {
defer pleasewait.Done()
process(w, cr) // doesn't work; no response :-(
}()
// process(w, cr) // works, but blank response :-(
pleasewait.Wait()
}
func main() {
http.HandleFunc("/add", handler)
}
答案 1 :(得分:1)
如果大型计算不使用共享可变状态,则编写普通处理程序。不需要频道,也没有频道。
好的,大型计算确实使用共享可变状态。如果只有一个应用程序实例正在运行,则使用sync.Mutex来控制对可变状态的访问。与将工作改组为单个goroutine以一次处理一个计算相比,这很简单。
你在App Engine上运行吗?您可能无法保证应用程序的单个实例正在运行。您需要将数据存储区或内存缓存用于可变状态。如果计算可以脱机完成(请求完成后),那么您可以使用App Engine任务队列一次处理一个计算。
附注:标题提出了解决问题正文中所述问题的方法。最好直接说明问题。我会在上面对此作出评论,但我没有必要的果汁。