使用golang通道时出现分段错误

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

Segmentation violation with golang channels

问题

以下代码打开了10,000个goroutine,它们进行HTTP调用,获取响应,关闭响应,并将响应写入带有ID的通道。

在第二个for循环中,它从缓冲通道中打印出前一个goroutine的ID。

这导致了一个段错误,我无法弄清楚原因。

恐慌:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x2293]

代码:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    requests := 10000
    ch := make(chan string, requests)
    for i := 1; i <= requests; i++ {
        go func(iter int) {
            fmt.Println(iter)
            resp, _ := http.Get("http://localhost:8080/api/project")
            resp.Body.Close()
            ch <- fmt.Sprint("%i", iter)
        }(i)
    }
    for i := 1; i <= requests; i++ {
        fmt.Println(<-ch)
    }
}
英文:

The below code opens 10,000 go routines, which make HTTP calls, get the response, close the response, and write to a channel with an ID.

In the second for loop, it prints out from that buffered channel the ID of the previous go routine.

This causes a segmentation violation, and I can't figure out why.

Panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x2293]

Code:

package main

import (
	&quot;fmt&quot;
	&quot;net/http&quot;
)

func main() {
	requests := 10000
	ch := make(chan string, requests)
	for i := 1; i &lt;= requests; i++ {
		go func(iter int) {
			fmt.Println(iter)
			resp, _ := http.Get(&quot;http://localhost:8080/api/project&quot;)
			resp.Body.Close()
			ch &lt;- fmt.Sprint(&quot;%i&quot;, iter)
		}(i)
	}
	for i := 1; i &lt;= requests; i++ {
		fmt.Println(&lt;-ch)
	}
}

答案1

得分: 6

你在调用API时没有检查任何错误,因此在尝试关闭一个从未到达的响应时会出现错误。

以下是不会引发错误的代码:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    requests := 10000
    ch := make(chan string, requests)
    for i := 1; i <= requests; i++ {
        go func(iter int) {
            fmt.Println(iter)
            resp, err := http.Get("http://localhost:8080/api/project")
            if err == nil {
                resp.Body.Close()
            }
            ch <- fmt.Sprint(iter)
        }(i)
    }
    for i := 1; i <= requests; i++ {
        fmt.Println(<-ch)
    }
}

希望对你有帮助!

英文:

You do not check for any error when calling the api. Thus the error when trying to close a response that never arrived.

This code does not panic:

package main

import (
    &quot;fmt&quot;
    &quot;net/http&quot;
)

func main() {
    requests := 10000
    ch := make(chan string, requests)
    for i := 1; i &lt;= requests; i++ {
        go func(iter int) {
            fmt.Println(iter)
            resp, err := http.Get(&quot;http://localhost:8080/api/project&quot;)
            if (err == nil) {
              resp.Body.Close()
            }
            ch &lt;- fmt.Sprint(iter)
        }(i)
    }
    for i := 1; i &lt;= requests; i++ {
        fmt.Println(&lt;-ch)
    }
}

答案2

得分: 2

这个错误的一般原因是当你尝试引用一个不存在或尚未创建的对象时。在上面的代码中,如果你在body不存在时尝试调用resp.Body.Close(),就会出现空指针引用的错误。

英文:

The general cause of this error is when you try to reference an object that does not exist or has not yet been created.

In the code above, if you try to call resp.Body.Close() when body does not exist, that becomes a nil pointer reference and hence the error.

huangapple
  • 本文由 发表于 2017年1月26日 02:10:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/41858635.html
匿名

发表评论

匿名网友

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

确定