doutong7216 2017-07-26 16:05
浏览 89

golang:防止由于对等错误而导致连接重置的策略

The program is spawning many goroutines (getStock) simultaneously which, I believe, is resulting in the remote server immediately dropping the connection. I am not trying to create a DOS, but I still want to aggressively get data without getting 'connection reset' errors.

What are some strategies to only have at most N (eg. 20) simultaneous connections? Is there a built-in queue for GET requests in the golang Http client? I'm still learning go it would be great to understand if there are better design patterns for this type of code.

Output

$ go run s1w.go 
sl(size): 1280
body: "AAPL",17.92
body: "GOOG",32.13
body: "FB",42.02
body: "AMZN",195.83
body: "GOOG",32.13
body: "AMZN",195.83
body: "GOOG",32.13
body: "FB",42.02
body: "AAPL",17.92
2017/07/26 00:01:23 NFLX: Get http://goanuj.freeshell.org/go/NFLX.txt: read tcp 192.168.86.28:56674->205.166.94.30:80: read: connection reset by peer
2017/07/26 00:01:23 AAPL: Get http://goanuj.freeshell.org/go/AAPL.txt: read tcp 192.168.86.28:56574->205.166.94.30:80: read: connection reset by peer
2017/07/26 00:01:23 NFLX: Get http://goanuj.freeshell.org/go/NFLX.txt: read tcp 192.168.86.28:56760->205.166.94.30:80: read: connection reset by peer
2017/07/26 00:01:23 FB: Get http://goanuj.freeshell.org/go/FB.txt: read tcp 192.168.86.28:56688->205.166.94.30:80: read: connection reset by peer
2017/07/26 00:01:23 AMZN: Get http://goanuj.freeshell.org/go/AMZN.txt: read tcp 192.168.86.28:56689->205.166.94.30:80: read: connection reset by peer
2017/07/26 00:01:23 AAPL: Get http://goanuj.freeshell.org/go/AAPL.txt: read tcp 192.168.86.28:56702->205.166.94.30:80: read: connection reset by peer

s1.go

package main
import (
        "fmt"
        "io/ioutil"
        "log"
        "net/http"
        "time"
)

// https://www.youtube.com/watch?v=f6kdp27TYZs (15m)
// Generator: function that returns a channel
func getStocks(sl []string) <-chan string {
        c := make(chan string)
        for _, s := range sl {
                go getStock(s, c)
        }
        return c
}

func getStock(s string, c chan string) {
        resp, err := http.Get("http://goanuj.freeshell.org/go/" + s + ".txt")
        if err != nil {
                log.Printf(s + ": " + err.Error())
                c <- err.Error() // channel send
                return
        }
        body, _ := ioutil.ReadAll(resp.Body)
        resp.Body.Close() // close ASAP to prevent too many open file desriptors
        val := string(body)
        //fmt.Printf("body: %s", val)
        c <- val // channel send
        return
}

func main() {
        start := time.Now()
        var sl = []string{"AAPL", "AMZN", "GOOG", "FB", "NFLX"}
        // creates slice of 1280 elements
        for i := 0; i < 8; i++ {
                sl = append(sl, sl...)
        }
        fmt.Printf("sl(size): %d
", len(sl))

        // get channel that returns only strings
        c := getStocks(sl)
        for i := 0; i < len(sl); i++ {
                fmt.Printf("%s", <-c) // channel recv
        }

        fmt.Printf("main: %.2fs elapsed.
", time.Since(start).Seconds())
}
  • 写回答

2条回答 默认 最新

  • dqxhit3376 2017-07-26 16:19
    关注

    Instead of spinning up new goroutines for every request, create a fixed pool when your program starts and pass in orders over a shared channel. Each order would be a struct corresponding to the parameters currently passed to getStock. Things get more complicated if you need to be able to kill the pool, but it still isn't that hard...

    Basically your new handler would be a loop, reading an order from a channel shared by all handlers, executing it, then sending the result on the order's response channel.

    评论

报告相同问题?

悬赏问题

  • ¥15 孟德尔随机化结果不一致
  • ¥20 求用stm32f103c6t6在lcd1206上显示Door is open和password:
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法