在http处理程序中使用goroutines和通道

huangapple go评论75阅读模式
英文:

Using goroutines and channels in a http handler

问题

我现在已经实现了一个非常简单的Twitter客户端阅读器:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

type twitterResult struct {
    Results []struct {
        Text     string `json:"text"`
        Ids      string `json:"id_str"`
        Name     string `json:"from_user_name"`
        Username string `json:"from_user"`
        UserId   string `json:"from_user_id_str"`
    }
}

var (
  twitterUrl = "http://search.twitter.com/search.json?q=%23UCL"
  pauseDuration = 5 * time.Second
)

func retrieveTweets(c chan<- *twitterResult) {
    for {
        resp, err := http.Get(twitterUrl)
        if err != nil {
            log.Fatal(err)
        }

        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        r := new(twitterResult) //or &twitterResult{} which returns *twitterResult
        err = json.Unmarshal(body, &r)
        if err != nil {
            log.Fatal(err)
        }
        c <- r
        time.Sleep(pauseDuration)
    }

}

func displayTweets(c chan *twitterResult) {
    tweets := <-c
    for _, v := range tweets.Results {
        fmt.Printf("%v:%v\n", v.Username, v.Text)
    }

}

func main() {
    c := make(chan *twitterResult)
    go retrieveTweets(c)
    for {
        displayTweets(c)
    }

}

我现在想为它构建一个简单的Web客户端,并显示Twitter的结果。但是我对在HTTP处理程序中调用goroutine持谨慎态度。有人能指点我正确的方向吗?

英文:

I've implemented a very simple twitter client reader:

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;time&quot;
)

type twitterResult struct {
	Results []struct {
		Text     string `json:&quot;text&quot;`
		Ids      string `json:&quot;id_str&quot;`
		Name     string `json:&quot;from_user_name&quot;`
		Username string `json:&quot;from_user&quot;`
		UserId   string `json:&quot;from_user_id_str&quot;`
	}
}

var (
  twitterUrl = &quot;http://search.twitter.com/search.json?q=%23UCL&quot;
  pauseDuration = 5 * time.Second
)

func retrieveTweets(c chan&lt;- *twitterResult) {
	for {
		resp, err := http.Get(twitterUrl)
		if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		r := new(twitterResult) //or &amp;twitterResult{} which returns *twitterResult
		err = json.Unmarshal(body, &amp;r)
		if err != nil {
			log.Fatal(err)
		}
		c &lt;- r
		time.Sleep(pauseDuration)
	}

}

func displayTweets(c chan *twitterResult) {
	tweets := &lt;-c
	for _, v := range tweets.Results {
		fmt.Printf(&quot;%v:%v\n&quot;, v.Username, v.Text)
	}

}

func main() {
	c := make(chan *twitterResult)
	go retrieveTweets(c)
	for {
		displayTweets(c)
	}

}

I want to build a simple web client for it now and have it display the twitter results. But i'm cautious about calling goroutines in a http handler. Anybody point me in the right direction?

答案1

得分: 2

你在HTTP请求的上下文中使用goroutines有一些限制,因为HTTP请求期望的是一个响应,而不是“等待到以后”。以下是几个选项:

  1. 使用Websockets。我从未在Go中实现过Websockets,所以在这方面没有任何经验,但这确实是让客户端等待数据并在数据到达时显示的最佳方式。这篇博客文章似乎有一个很好的教程。(你也可以使用COMET框架来实现类似的效果。)

  2. 不使用goroutines,而是使用AJAX请求来保持客户端的异步性。这样的话,客户端加载你的页面后,会向服务器发送一系列的AJAX请求,你可以在多个线程中处理这些请求,这样它们理论上可以在大致相同的时间内全部完成。请注意,你可以生成一个goroutine来响应特定的请求,但是这个goroutine应该能够完全响应该请求。

  3. 使用goroutines来发起所有的Twitter API请求,但是等待它们全部完成并将它们合并在一起,然后再完成请求并生成响应。这样可以让所有的Twitter API请求同时进行,从而节省后端的时间,但是客户端仍然需要等待这段时间(最慢的API请求)才能向用户显示任何内容。

如果是我,而且我很着急,我会选择选项2,将繁重的工作留给客户端,而只将服务器作为一个代理来使用Twitter API。但是选项1可能是一个更好的解决方案,特别是如果你对浏览器的兼容性不太担心。

英文:

You're sort of limited with goroutines within the context of an HTTP request because that HTTP request expects a response, not a "wait until later". Here are a couple options:

  1. Use websockets. I've never implemented a websocket in Go, so I don't have any experience there, but this is really the best way to have the client wait for data and display it as it comes in. This blog post seems to have a good tutorial. (You could also use a COMET framework to achieve something similar here.)

  2. Don't use goroutines, but rather AJAX requests to keep the asynchronousness (totally a word) on the client. What that would look like is the client loading your page, which makes a bunch of AJAX requests to your server, which you can handle in multiple threads so they could theoretically all finish around the same time. Note that you can spawn a goroutine to respond to a specific request, but that goroutine should be expected to respond to that request fully.

  3. Use goroutines to make all your requests to the Twitter API, but wait for them all to finish and lump them all together before completing the request and making the response. This lets all your Twitter API requests happen simultaneously and saves you time on the backend, but your client still has to wait for that time (the slowest API request) before showing anything to the user.

If it were me and I were in a hurry, I'd go with option 2 and leave the heavy lifting to the client, while just using the server as basically a proxy to the Twitter API. But option 1 would be a better solution, especially if you're not too worried about browser compatibility.

huangapple
  • 本文由 发表于 2013年4月5日 03:29:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/15820046.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定