goroutines用完内存 UPD:go错误处理

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

goroutines run out of memory UPD: go error handling

问题

<b>UPD</b>:原来,这是关于Go语言中错误处理的问题。

我写了一个简单的网络爬虫,它在“主线程”上生成网页地址,使用一个go协程获取实际页面,并通过一个chan返回内容,然后在另一个go协程中将其写入文件。然而,在大约300,000次迭代后,我遇到了以下错误:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x38 pc=0x22e9]

这个错误的“堆栈跟踪”非常长,不幸的是,我现在没有它(我会在重复实验后稍后发布它)。

是否需要以某种方式管理内存,关闭通道或类似的操作?

以下是一些省略的代码。

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "strconv"
)

func main() {
    channel := make(chan []byte)

    for i:=0; i < 20; i++ {
        go fetcher(generateLink(), channel)
    }

    for a:=0; ; a++ {
        go writeToFile(strconv.Itoa(a), <-channel)
        go fetcher(generateLink(), channel)
        fmt.Println(strconv.Itoa(a))
    }
}

func fetcher(url string, channel chan []byte) {

    resp, err := http.Get(url)
    if err != nil {
        channel <- []byte("")
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    channel <- body
}

func writeToFile(filename string, bytes []byte) {
    ioutil.WriteFile(filename+".html", bytes, 0644)
}

func generateLink() string {
    ...
}
英文:

<b>UPD</b>: Turns out, it is a question about error handling in Go

I have written a simple web crawler, that generates the addresses of web-pages on the "main thread", fetches the actual pages in one go-routine and gives the content back via a chan, and writes it to a file in another go-routine. However, after about 300,000 iterations of this process, i get the following error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x38 pc=0x22e9]&lt;/pre&gt;

The error "stacktrace" is quite long, and unfotunately, I don't have it now (I will post it later, after repeating the experiment).

Is there a need to somehow manage the memory, close the channels or something like that?

Below is the code with some omissions.

package main

import (
	&quot;fmt&quot;
	&quot;io/ioutil&quot;
	&quot;net/http&quot;
	&quot;strconv&quot;
)

func main() {
	channel := make(chan []byte)

	for i:=0; i &lt; 20; i++ {
		go fetcher(generateLink(), channel)
	}

	for a:=0; ; a++ {
		go writeToFile(strconv.Itoa(a), &lt;-channel)
		go fetcher(generateLink(), channel)
		fmt.Println(strconv.Itoa(a))
	}
}

func fetcher(url string, channel chan []byte) {

	resp, err := http.Get(url)
	if err != nil {
		channel &lt;- []byte(&quot;&quot;)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	channel &lt;- body
}

func writeToFile(filename string, bytes []byte) {
	ioutil.WriteFile(filename+&quot;.html&quot;, bytes, 0644)
}

func generateLink() string {
	...
}

答案1

得分: 3

恐慌:运行时错误:无效的内存地址或空指针解引用

这意味着您尝试使用空指针。这是程序员的错误,而不是内存不足错误。由于我无法访问实际的跟踪或代码,所以无法再帮助您。

**编辑:**在再次查看您的代码后,我认为找到了可能导致错误的原因。

resp, err := http.Get(url)
if err != nil {
    channel <- []byte("")
}
defer resp.Body.Close()

即使err != nil,您最终仍然引用resp以获取Body字段。如果err != nil,那么resp很可能是空指针。

英文:
panic: runtime error: invalid memory address or nil pointer deference

This means you tried to use a nil pointer. This is a programmer error, not an out of memory error. Since I don't have access to the actual trace or code, there is no way I can help you further.

<br>

Edit: After taking another look at your code I think I found a possible source of the error.

resp, err := http.Get(url)
if err != nil {
    channel &lt;- []byte(&quot;&quot;)
}
defer resp.Body.Close()

You end up referencing resp in order to get the field Body even when err != nil. If err !=nil, it is quite likely resp is nil.

答案2

得分: 1

我只是猜测,因为我没有堆栈跟踪。但是以下两行代码对我来说看起来很可疑:

body, err := ioutil.ReadAll(resp.Body)
channel <- body

你怎么知道在将其发送到通道时,body不是nil?由于writeToFile也没有检查它,所以完全有可能你正在尝试将一个nil字节切片写入文件,然后它就会出错。如果你捕获了一个错误,应该在继续之前检查它。

英文:

I'm only guessing here since I don't have the stacktrace. but the following two lines look suspicious to me:

body, err := ioutil.ReadAll(resp.Body)
channel &lt;- body

How do you know the body is not nil when you send it on the channel? Since writeToFile doesn't check it either it's totally possible that you are tring to write a nil byte slice to the file and it's blowing up there. If you capture an err you should check it before going on.

答案3

得分: 1

在某个时候,你调用http.Get()失败并返回一个非空的err。当这种情况发生时,你将一个空的字节切片放入通道中,但你继续进行,并尝试从resp.Body读取,而此时resp是空的。

英文:

At some point, your call to http.Get() fails and returns a non-nil err. When this happens, you put an empty byte slice into the channel, but you keep going, and try to read from resp.Body anyway, when resp is nil.

huangapple
  • 本文由 发表于 2012年8月18日 04:12:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/12012581.html
匿名

发表评论

匿名网友

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

确定