【发布时间】:2019-07-04 14:17:49
【问题描述】:
我已经在端口上运行 Web 服务器并处理发布请求,该请求在内部调用不同的 url 以使用 goroutine 获取响应并继续。
我已将整个流程划分为不同的方法。代码草稿。
package main
import (
"bytes"
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
"time"
)
var status_codes string
func main() {
router := mux.NewRouter().StrictSlash(true)
/*router := NewRouter()*/
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "Hello!!!")
})
router.HandleFunc("/{name}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
prepare(w, r, vars["name"])
}).Methods("POST")
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", 8080), router))
}
func prepare(w http.ResponseWriter, r *http.Request, name string) {
//initializing for the current request, need to maintain this variable for each request coming
status_codes = ""
//other part of the code and call to goroutine
var urls []string
//lets say all the url loaded, call the go routine func and wait for channel to respond and then proceed with the response of all url
results := callUrls(urls)
process(w, results)
}
type Response struct {
status int
url string
body string
}
func callUrls(urls []string) []*Response {
ch := make(chan *Response, len(urls))
for _, url := range urls {
go func(url string) {
//http post on url,
//base on status code of url call, add to status code
//some thing like
req, err := http.NewRequest("POST", url, bytes.NewBuffer(somePostData))
req.Header.Set("Content-Type", "application/json")
req.Close = true
client := &http.Client{
Timeout: time.Duration(time.Duration(100) * time.Second),
}
response, err := client.Do(req)
if err != nil {
status_codes += "200,"
//do other thing with the response received
} else {
status_codes += "500,"
}
// return to channel accordingly
ch <- &Response{200, "url", "response body"}
}(url)
}
var results []*Response
for {
select {
case r := <-ch:
results = append(results, r)
if len(results) == len(urls) {
//Done
close(ch)
return results
}
}
}
}
func process(w http.ResponseWriter, results []*Response){
//read those status code received from all urls call for the given request
fmt.Println("status", status_codes)
//Now the above line keep getting status code from other request as well
//for eg. if I have called 5 urls then it should have
//200,500,204,404,200,
//but instead it is
//200,500,204,404,200,204,404,200,204,404,200, and some more keep growing with time
}
上面的代码是这样的:
- 全局变量声明,在准备函数中初始化。
- 在 goroutine callUrls 函数中附加值
- 在处理函数中读取那些变量
现在我应该将那些全局声明的变量传递给每个函数调用以使其成为本地变量,因为那时它不会被共享吗?(我不想这样做。)
或者有没有其他方法可以在不向被调用函数添加更多参数的情况下实现相同的目标。
因为我将有很少的其他字符串和 int 值将在整个程序和 go 例程函数中使用。
使它们成为线程安全的正确方法是什么,并且每个请求同时在端口上只有 5 个代码。
【问题讨论】:
-
"现在我应该将那些全局声明的变量传递给每个函数调用以使它们成为本地变量,因为那时它不会被共享吗?" - 这个,加上
+=确实会在本地进行更改(并且毫无意义)。 -
如果你修改全局状态,你需要围绕它进行一些同步(互斥锁等)
-
我的意思是将它传递给每个函数就像在准备函数
status_codes := "" results := callUrls(urls, status_codes) process(w, results, status_codes ])中一样,因此在 callUrls 中将附加一个空变量,然后它可以在过程函数中使用。但正如我所说,我不想这样做。我遇到 Context 不确定这是否是我需要使用的东西。 -
"然后就可以在进程函数中使用"——可以,但是还是空的。
-
那么正确的方法是什么?
标签: go