我在网络服务器上运行了go服务器,并处理了post请求,该请求内部调用了不同的url以使用goroutine获取响应并继续。
我已将整个流程划分为不同的方法。代码草稿。
<style>
* {
box-sizing: border-box;
}
.header {
padding: 15px;
}
.menu {
padding: 5px;
margin: 0;
padding: 0;
width: 25%;
height: 100%;
background-color: #f1f1f1;
float: left;
overflow: auto;}
.main {
width: 75%;
float: left;
padding: 15px;
margin-left:25%;
padding:1px 16px;
height:1000px;
}
</style>
<div class="header">
<h1>Computer Networks</h1>
</div>
<hr>
<div class="menu">
<iframe id="bookpage" name="bookpage" src="Navigation.html"></iframe>
</div>
<div class="main">
<h1>The Content</h1>
<iframe id="content01" name="content01" src="courses/DCN/Computer Network Types.html"></iframe>
</div>
上面的代码可以做到:
现在我应该将全局声明的变量传递给每个函数调用,以使它们成为本地变量,因为那样一来就不会被共享?(我不愿意这样做)
或者是否有其他方法可以实现相同的目的而无需在调用的函数中添加更多参数。
因为我将在程序中以及go例程函数中使用的其他字符串和整数值也很少。
使它们成为线程安全的正确方法是什么,并且每个请求同时进入端口仅5个代码。
答案 0 :(得分:0)
请勿使用全局变量,而应使用显式变量并使用函数参数。此外,您在status_codes
上存在竞争条件,因为它可以由多个goroutine进行访问而没有任何互斥锁。
在下面查看我的修复程序。
func prepare(w http.ResponseWriter, r *http.Request, name string) {
var urls []string
//status_codes is populated by callUris(), so let it return the slice with values
results, status_codes := callUrls(urls)
//process() needs status_codes in order to work, so pass the variable explicitely
process(w, results, status_codes)
}
type Response struct {
status int
url string
body string
}
func callUrls(urls []string) []*Response {
ch := make(chan *Response, len(urls))
//In order to avoid race condition, let's use a channel
statusChan := make(chan string, 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 {
statusChan <- "200"
//do other thing with the response received
} else {
statusChan <- "500"
}
// return to channel accordingly
ch <- &Response{200, "url", "response body"}
}(url)
}
var results []*Response
var status_codes []string
for !doneRes || !doneStatus { //continue until both slices are filled with values
select {
case r := <-ch:
results = append(results, r)
if len(results) == len(urls) {
//Done
close(ch) //Not really needed here
doneRes = true //we are done with results, set the corresponding flag
}
case status := <-statusChan:
status_codes = append(status_codes, status)
if len(status_codes) == len(urls) {
//Done
close(statusChan) //Not really needed here
doneStatus = true //we are done with statusChan, set the corresponding flag
}
}
}
return results, status_codes
}
func process(w http.ResponseWriter, results []*Response, status_codes []string) {
fmt.Println("status", status_codes)
}