【发布时间】:2014-11-01 11:38:56
【问题描述】:
我正在尝试构建一个简单的 Golang/Appengine 应用程序,它使用一个通道来处理每个 http 请求。原因是我希望每个请求都执行合理的大内存计算,并且每个请求都以线程安全的方式执行很重要(即来自并发请求的计算不会混合)。
基本上我需要一个同步队列,它一次只处理一个请求,并且通道看起来很合适。
Is it possible to use Go's buffered channel as a thread-safe queue?
但是,我无法让我的简单 hello world 示例正常工作。它似乎在'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)
}
【问题讨论】:
-
仅供参考 - 你说的那个返回空白响应对我来说很好。不过,您的问题是,Go 将刷新响应,因为它认为它已经完成了它的工作。在此处使用
go来触发goroutine 将意味着您的处理代码在 请求被刷新之后运行。也就是说,ListenAndServe将为您处理并发。它实际上会在每个请求的循环中触发一个 goroutine(也就是说,您的处理程序已作为 goroutine 被触发)。那么您还想添加什么? -
ListenAndServe 听起来可能就是我要找的东西;但是它为每个请求线程触发的 goroutine 是否安全?还是我需要将它们与频道一起使用?
-
不,它们不是线程安全的——它们只是触发 goroutine 并继续监听。如果您共享全局状态,这实际上只是一个问题 - 在上面的示例中您似乎没有这样做。也就是说,您的大型计算可能有一些全局状态。所以这对您来说可能是个问题。
-
非常有用,谢谢。没有全局状态,但 calc 包含一些我知道不是线程安全的映射;将 http.HandleFunc 与 calc 结合使用似乎会导致线程错误,即 calc 结果都是错误的/混淆了。您认为使用 ListenAndServer/goroutines 可能会解决问题吗? [也许是因为 http.HandleFunc 在同一个线程/goroutine 中做所有事情?]
-
我认为你让这变得比它需要的更复杂。为什么不只使用请求处理程序的本地映射?在这种情况下,同步访问全局状态似乎并不能真正阻止事情变得混乱。
标签: google-app-engine concurrency go