簡體   English   中英

Golang Goroutine 與通道同步

[英]Golang Goroutine synchronization with channel

我有以下程序,其中使用 gorilla mux 創建 HTTP 服務器。 當任何請求到來時,它會啟動 goroutine 1。在處理過程中,我正在啟動另一個 goroutine 2。我想在 goroutine 1 中等待 goroutine 2 的響應? 我怎么能做到這一點? 如何確保只有 goroutine 2 會響應 goroutine 1?

GR3 可以創建 GR4,GR 3 應該只等待 GR4。

GR = 協程

在此處輸入圖片說明

服務器

    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))
}

結果實際

{"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)
}

我懷疑您是新手,這是一個基本的頻道用法,請在此處查看更多詳細信息頻道

所以你遇到的問題是你還沒有真正傾向於如何處理並發代碼(不是dis,我曾經在那里)。 其中大部分都不是圍繞渠道。 正如@kojan 的回答所解釋的那樣,頻道工作正常。 事情出錯的地方是i變量。 首先,您必須了解i沒有被原子地變異,因此如果您的客戶端請求並行到達,您可能會弄亂數字:

C1 :          C2:
i == 6        i == 6
i++           i++
i == 7        i == 7

軟件中的兩個增量實際上變成了一個增量,因為i++實際上是 3 個操作:加載、增量、存儲。

你遇到的第二個問題是i不是一個指針,所以當你將i傳遞給你的 go 例程時,你正在制作一個副本。 go 例程中的i被發送回通道,並成為您可以觀看增量的連接字符串中的第一個數字。 然而,在字符串尾部使用的i繼續通過連續的客戶端調用而增加。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM