Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
229 views
in Technique[技术] by (71.8m points)

go - How to share one HTTP request instance beween two goroutines?

I have some code that makes 3 requests to fill 3 variables now. Two requests are same. I want to share one http request between two different functions (in real world, these functions are splitted into two different modules).

Let me describe the problem what I have based on much simpler example than I have in real world.

At the moment, I have the following main function and Post data structure:

type Post struct {
    ID          int    `json:"id"`
    Title       string `json:"title"`
    UserID      int    `json:"userId"`
    isCompleted bool   `json:"completed"`
}

func main() {
    var wg sync.WaitGroup

    fmt.Println("Hello, world.")

    wg.Add(3)

    var firstPostID int
    var secondPostID int
    var secondPostName string

    go func() {
        firstPostID = getFirstPostID()
        defer wg.Done()
    }()

    go func() {
        secondPostID = getSecondPostID()
        defer wg.Done()
    }()

    go func() {
        secondPostName = getSecondPostName()
        defer wg.Done()
    }()

    wg.Wait()

    fmt.Println("first post id is", firstPostID)
    fmt.Println("second post id is", secondPostID)
    fmt.Println("second post title is", secondPostName)
}

There are three goroutines, so I have 3 concurrent requests, I sync everything using sync.Workgroup. The following code is implementation of the requests:

func makeRequest(url string) Post {
    resp, err := http.Get(url)
    if err != nil {
        // handle error
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    var post Post

    json.Unmarshal(body, &post)

    return post
}

func makeFirstPostRequest() Post {
    return makeRequest("https://jsonplaceholder.typicode.com/todos/1")
}

func makeSecondPostRequest() Post {
    return makeRequest("https://jsonplaceholder.typicode.com/todos/2")
}

Here is implementation of functions which pulls needed information from fetched posts:

func getFirstPostID() int {
    var result = makeFirstPostRequest()
    return result.ID
}

func getSecondPostID() int {
    var result = makeSecondPostRequest()

    return result.ID
}

func getSecondPostName() string {
    var result = makeSecondPostRequest()

    return result.Title
}

So, at the moment I have 3 concurrent requests, this works perfectly. The problem is I don't want 2 absolutely same separate HTTP requests to fetch the second post. One would be enough. So, what I want to achieve is 2 concurrent requests for post 1 and post 2. I want second call to makeSecondPostRequest not to create new HTTP request, but share the existing one (which was sent by the first call).

How I can achieve this?

Note: the following code is how this can be done using JavaScript, for example.

let promise = null;
function makeRequest() {
    if (promise) {
        return promise;
    }

    return promise = fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(result => result.json())
      // clean up cache variable, so any next request in the future will be performed again
      .finally(() => (promise = null))

}

function main() {
    makeRequest().then((post) => {
        console.log(post.id);
    });
    makeRequest().then((post) => {
        console.log(post.title);
    });
}

main();
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...