doucan1996 2015-07-20 23:25
浏览 288
已采纳

发出HTTP请求时打开的文件过多

I am trying to create a http client program in go which would make many http GET requests. I am using a buffered channel to limit the number of concurrent requests.

When I run the program I get

Get http://198.18.96.213/: dial tcp 198.18.96.213:80: too many open files

Here is my program:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func HttpGets(numRequests int, numConcurrent int, url string) map[int]int {
    // I want number of requests with each status code
    responseStatuses := map[int]int {
        100: 0, 101 : 0, 102 : 0, 200 : 0, 201 : 0, 202 : 0, 203 : 0, 204 : 0, 205 : 0, 
        206 : 0, 207 : 0, 208 : 0, 226 : 0, 300 : 0, 301 : 0, 302 : 0, 303 : 0, 304 : 0, 
        305 : 0, 306 : 0, 307 : 0, 308 : 0, 400 : 0, 401 : 0, 402 : 0, 403 : 0, 404 : 0, 
        405 : 0, 406 : 0, 407 : 0, 408 : 0, 409 : 0, 410 : 0, 411 : 0, 412 : 0, 413 : 0, 
        414 : 0, 415 : 0, 416 : 0, 417 : 0, 421 : 0, 422 : 0, 423 : 0, 424 : 0, 425 : 0, 
        426 : 0, 427 : 0, 428 : 0, 429 : 0, 430 : 0, 431 : 0, 500 : 0, 501 : 0, 502 : 0, 
        503 : 0, 504 : 0, 505 : 0, 506 : 0, 507 : 0, 508 : 0, 509 : 0, 510 : 0, 511 : 0, 
    }

    reqsDone := 0
    ch := make(chan *http.Response, numConcurrent)
    for i := 0; i < numRequests; i++ {
        go func(url string) {
            client := &http.Client{}
            req, reqErr := http.NewRequest("GET", url, nil)
            if reqErr != nil {
                fmt.Println(reqErr)
            }
            // adding connection:close header hoping to get rid 
            // of too many files open error. Found this in http://craigwickesser.com/2015/01/golang-http-to-many-open-files/           
            req.Header.Add("Connection", "close") 

            resp, err := client.Do(req)
            if (err !=nil) {
                fmt.Println(err)
            }
            ch <- resp

        }(url)
    }

    for {
        select {
        case r := <-ch:
            reqsDone += 1 // probably needs a lock?
            status := r.StatusCode          
            if _, ok := responseStatuses[status]; ok {
                responseStatuses[status] += 1           

            } else {
                responseStatuses[status] = 1
            }
            r.Body.Close() // trying to close body hoping to get rid of too many files open error 
            if (reqsDone == numRequests) {
                return responseStatuses
            }    
        }
    }
    return responseStatuses
}

func main() {
    var numRequests, numConcurrent = 500, 10
    url := "http://198.18.96.213/"
    beginTime := time.Now()
    results := HttpGets(numRequests, numConcurrent, url)
    endTime := time.Since(beginTime)
    fmt.Printf("Total time elapsed: %s
", endTime)
    for k,v := range results {
        if v!=0 {
            fmt.Printf("%d : %d
", k, v)
        }       
    }

}

How to I ensure files/socets are closed so that I don't get this error when making multiple requests?

  • 写回答

2条回答 默认 最新

  • doubaoguo7469 2015-07-21 00:07
    关注

    Basically you were spawning 100s of goroutines that will start the connection the block until they are closed.

    Here's a quick (and very ugly) working code:

    var (
        responseStatuses = make(map[int]int, 63)
        reqsDone         = 0
    
        urlCh = make(chan string, numConcurrent)
        ch    = make(chan *http.Response, numConcurrent)
    )
    log.Println(numConcurrent, numRequests, len(responseStatuses))
    for i := 0; i < numConcurrent; i++ {
        go func() {
            for url := range urlCh {
                client := &http.Client{}
                req, reqErr := http.NewRequest("GET", url, nil)
                if reqErr != nil {
                    fmt.Println(reqErr)
                }
                // adding connection:close header hoping to get rid
                // of too many files open error. Found this in http://craigwickesser.com/2015/01/golang-http-to-many-open-files/
                req.Header.Add("Connection", "close")
    
                resp, err := client.Do(req)
                if err != nil {
                    fmt.Println(err)
                }
                ch <- resp
            }
    
        }()
    }
    go func() {
        for i := 0; i < numRequests; i++ {
            urlCh <- url
        }
        close(urlCh)
    }()
    

    <kbd>playground</kbd>

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 matlab实现基于主成分变换的图像融合。
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊