繁体   English   中英

Golang:使用Go Routines和JSON进行HTTP调用并解析JSON

[英]Golang: Make HTTP call and parse JSON with Go Routines and JSON

我对golang比较陌生,我想创建一种方法来同时调用多个URL,并解析JSON文档。 但是,我真的不确定我是否正确使用了go例程和通道。 在这一点上,我不确定我是否正确地“思考”,或者我对goroutine和渠道的理解/方法不正确。

此外,在解析时,我想从主体(一个数组)中解析results属性,并且results中的每个元素都包含一个我想过滤掉的doc属性。

目标是同时进行多个提取,并仅解析响应主体结果数组中的doc属性的响应。

一定会感谢您的任何见解或建议,以更好地理解事物。 提前致谢。

package operations

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "strings"
)

// CouchbaseDoc parses .doc property from sync gateway documents
type CouchbaseDoc struct {
    Doc map[string]string `json:"doc"`
}

// Results deconstruct... results is a property of body, and is an array of obects
type Results struct {
    Results []byte `json:"results"`
}

func createURLs(channels []string) map[string]string {
    urlMap := make(map[string]string)

    domain := "swap" + strings.TrimSpace(os.Getenv("env"))
    bucket := strings.TrimSpace(os.Getenv("bucket"))
    for _, doctype := range channels {
        urlMap[doctype] = fmt.Sprintf("https://%s.endpoint.com/%s/_changes?filter=sync_gateway/bychannel&channels=%s&include_docs=true", domain, bucket, doctype)
    }

    return urlMap
}

func getChangesFeed(url string, ch chan map[string]string) {
    resp, _ := http.Get(url)

    body, _ := ioutil.ReadAll(resp.Body)

    go parseBody(body, ch)
}

func parseBody(body []byte, ch chan map[string]string) {
    var results Results
    var doc CouchbaseDoc
    json.Unmarshal(body, &results)
    json.Unmarshal(results.Results, &doc)
    // write to responses
    ch <- doc.Doc
}

func fetchDocs(channels []string) {
    urls := createURLs(channels)

    // Response channel is where all go routines will do the dirty
    responses := make(chan map[string]string)
    for _, url := range urls {
        go getChangesFeed(url, responses)
    }

    // Read from responses channel
    docs := <-responses
    for doc := range docs {
        fmt.Println(doc) // This should print results ??
    }
}

修复

这行:

docs := <-responses

将仅从通道接收一个元素,而不是所有元素。 但是,您可以在通道上每个预期的发送调用一次接收操作,这将是代码的最简单修复:

responses := make(chan map[string]string)
for _, url := range urls {
    go getChangesFeed(url, responses)
}

for x := 0; x < len(urls); x++ {
    fmt.Println(<-responses)
}

更多信息

请注意,由于未给通道指定长度,所以您使用的是无缓冲通道。 for e := range ch {循环仅适用于缓冲通道,并且仅在缓冲通道关闭后才适用。

关闭缓冲的通道表示将不再在该通道上发送任何数据,并且可能与您的程序设计不符(尤其是没有sync.WaitGroup )。

因此,使用缓冲的通道就可以了:您只需要知道发送和接收操作都不会进行,除非双方都准备好:这意味着双方都被阻塞并等待对方。

使用上面的代码,可以通过将sends放入goroutine中,并使用带有相等计数器的循环在主goroutine中排队相等数量的接收操作来轻松实现这一点。

要了解更多信息,请阅读sync软件包文档中 的语言规范Effective Go以及Mutex和WaitGroup部分。

可运行的演示

这是一个完整的可运行示例,演示了该原理:

package main

import(
    "fmt"
    "time"
)

func Sleep1(ch chan int) {
    time.Sleep(time.Second)
    ch <- 1
}

func Sleep3(ch chan int) {
    time.Sleep(time.Second * 3)
    ch <- 3
}

func Sleep5(ch chan int) {
    time.Sleep(time.Second * 5)
    ch <- 5
}

func main() {
    ch := make(chan int)
    go Sleep1(ch)
    go Sleep3(ch)
    go Sleep5(ch)
    for x := 0; x < 3; x++ {
        fmt.Println(<-ch)
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM