英文:
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]</pre>
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 (
"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 {
...
}
答案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 <- []byte("")
}
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 <- 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论