对于一个程序,我正在将此函数作为goroutine在for循环中运行,具体取决于传入的URL数量(没有设置数量)。
func makeRequest(url string, ch chan<- string, errors map[string]error){
res, err := http.Get(url)
if err != nil {
errors[url] = err
close(ch)
return
}
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
ch <- string(body)
}
必须使用整个响应,因此ioutil.ReadAll看起来很合适,但是对可以传递的url数量没有限制,并且ReadAll的性质是它全部存储在内存中,因此开始感觉不像黄金票。我是Go的新手,所以如果您决定回答,如果您可以在解决方案背后给出一些解释,将不胜感激!
答案 0 :(得分:3)
为了进行bound the amount of memory that you're application is using,常见的方法是读入缓冲区,该缓冲区应直接解决您的ioutil.ReadAll
问题。
go的bufio
软件包提供实用程序(Scanner
),该实用程序支持读取直到分隔符或从输入中读取一行,这与@Howl的问题高度相关
答案 1 :(得分:1)
当我学习如何使用Go时,我得到的一个见解是,对于所有读者来说,ReadAll通常效率不高,并且像您的情况一样,它受到任意输入很大的影响,并且可能会浪费内存。一开始,我曾经像这样进行JSON解析:
data, err := ioutil.ReadAll(r)
if err != nil {
return err
}
json.Unmarshal(data, &v)
然后,我了解了一种解析JSON的更有效的方法,该方法就是简单地使用Decoder
类型。
err := json.NewDecoder(r).Decode(&v)
if err != nil {
return err
}
这不仅更加简洁,而且在内存方面和时间方面都更加高效:
Read
方法结合使用以获取所有数据并进行解析。这样可以节省大量的分配时间,并消除了GC的压力现在,您的问题当然与JSON无关,但是该示例非常有用,它说明了如果您可以直接使用Read
并一次解析数据块,则可以这样做。特别是对于HTTP请求,解析比读取/下载要快,因此这可能导致解析的数据几乎在请求正文到达时就立即准备就绪。
在您的情况下,您似乎暂时还没有对数据进行任何处理,因此没有太多建议可以帮助您。但是io.Reader
和io.Writer
接口相当于UNIX管道的Go语言,因此您可以在许多不同的地方使用它们:
将数据写入文件:
f, err := os.Create("file")
if err != nil {
return err
}
defer f.Close()
// Copy will put all the data from Body into f, without creating a huge buffer in memory
// (moves chunks at a time)
io.Copy(f, resp.Body)
将所有内容打印到标准输出:
io.Copy(os.Stdout, resp.Body)
将响应的正文放置到请求的正文中:
resp, err := http.NewRequest("POST", "https://example.com", resp.Body)
答案 2 :(得分:0)
尽管这很简单
这是客户端程序:
package main
import (
"fmt"
"net/http"
)
var data []byte
func main() {
data = make([]byte, 128)
ch := make(chan string)
go makeRequest("http://localhost:8080", ch)
for v := range ch {
fmt.Println(v)
}
}
func makeRequest(url string, ch chan<- string) {
res, err := http.Get(url)
if err != nil {
close(ch)
return
}
defer res.Body.Close()
defer close(ch) //don't forget to close the channel as well
for n, err := res.Body.Read(data); err == nil; n, err = res.Body.Read(data) {
ch <- string(data[:n])
}
}
这是服务程序:
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe("localhost:8080", nil)
}
func hello(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "movie.mkv")
}