我有以下程序,其中使用大猩猩mux创建HTTP服务器。当有任何请求到达时,它将启动goroutine1。在处理中,我正在启动另一个goroutine 2。我想等待goroutine 1中goroutine 2的响应吗?我该怎么做?如何确保只有goroutine 2会响应goroutine 1?]
可能存在由GR3创建的GR4,并且GR 3仅应等待GR4。
GR = Goroutine
SERVER
package main
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/gorilla/mux"
)
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
var posts []Post
var i = 0
func getPosts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
i++
fmt.Println(i)
ch := make(chan int)
go getTitle(ch, i)
p := Post{
ID: "123",
}
// Wait for getTitle result and update variable P with title
s := <-ch
//
p.Title = strconv.Itoa(s) + strconv.Itoa(i)
json.NewEncoder(w).Encode(p)
}
func main() {
router := mux.NewRouter()
posts = append(posts, Post{ID: "1", Title: "My first post", Body: "This is the content of my first post"})
router.HandleFunc("/posts", getPosts).Methods("GET")
http.ListenAndServe(":9999", router)
}
func getTitle(resultCh chan int, m int) {
time.Sleep(2 * time.Second)
resultCh <- m
}
客户
package main
import (
"fmt"
"net/http"
"io/ioutil"
"time"
)
func main(){
for i :=0;i <100 ;i++ {
go main2()
}
time.Sleep(200 * time.Second)
}
func main2() {
url := "http://localhost:9999/posts"
method := "GET"
client := &http.Client {
}
req, err := http.NewRequest(method, url, nil)
if err != nil {
fmt.Println(err)
}
res, err := client.Do(req)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
RESULT ACTUAL
{"id":"123","title":"25115","body":""}
{"id":"123","title":"23115","body":""}
{"id":"123","title":"31115","body":""}
{"id":"123","title":"44115","body":""}
{"id":"123","title":"105115","body":""}
{"id":"123","title":"109115","body":""}
{"id":"123","title":"103115","body":""}
{"id":"123","title":"115115","body":""}
{"id":"123","title":"115115","body":""}
{"id":"123","title":"115115","body":""}
期望结果
{"id":"123","title":"112112","body":""}
{"id":"123","title":"113113","body":""}
{"id":"123","title":"115115","body":""}
{"id":"123","title":"116116","body":""}
{"id":"123","title":"117117","body":""}
有几种方法,一种简单的方法是使用频道
将getTitle函数更改为此
func getTitle(resultCh chan string) {
time.Sleep(2 * time.Second)
resultCh <- "Game Of Thrones"
}
和getPosts将像这样使用它
func getPosts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
ch := make(chan string)
go getTitle(ch)
s := <-ch // this will wait until getTile inserts data to channel
p := Post{
ID: s,
}
json.NewEncoder(w).Encode(p)
}
我怀疑您是新手,这是基本的频道用法,请在此处查看更多详细信息Channels
所以您遇到的问题是,您还没有真正了解如何处理并发代码(不是dis,我曾经去过那里)。大多数此类活动不在渠道周围。如@kojan的答案所述,通道正常工作。出错的地方是i
变量。首先,您必须了解i
并不是原子突变的,因此,如果您的客户请求并行到达,您可能会弄乱数字:
C1 : C2:
i == 6 i == 6
i++ i++
i == 7 i == 7
软件中的两个增量实际上是一个增量,因为i++
实际上是3个操作:加载,增量,存储。
您遇到的第二个问题是i
不是指针,因此当您将i
传递给go例程时,您正在制作一个副本。 go例程中的i
被发送回通道,并成为连接字符串中的第一个数字,您可以观看其增量。但是,在字符串尾部使用的i
仍然通过连续的客户端调用来增加。