当调用`http.Get`时,Golang会在发生错误时抛出`panic`异常。

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

golang panic when invoke http.Get

问题

错误消息:

  1. goroutine 11357 [可运行]:
  2. net.runtime_pollWait(0x1737f28, 0x77, 0x4fa90)
  3. /usr/local/go/src/runtime/netpoll.go:157 +0x60
  4. net.(*pollDesc).Wait(0xc829571bf0, 0x77, 0x0, 0x0)
  5. /usr/local/go/src/net/fd_poll_runtime.go:73 +0x3a
  6. net.(*pollDesc).WaitWrite(0xc829571bf0, 0x0, 0x0)
  7. /usr/local/go/src/net/fd_poll_runtime.go:82 +0x36
  8. net.(*netFD).connect(0xc829571b90, 0x0, 0x0, 0x1714f80, 0xc829572f20, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0)
  9. /usr/local/go/src/net/fd_unix.go:114 +0x1f6
  10. net.(*netFD).dial(0xc829571b90, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0)
  11. /usr/local/go/src/net/sock_posix.go:137 +0x351
  12. net.socket(0x3050e8, 0x3, 0x2, 0x1, 0x0, 0xc829575500, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, ...)
  13. /usr/local/go/src/net/sock_posix.go:89 +0x411
  14. net.internetSocket(0x3050e8, 0x3, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, 0xece412272, 0xc833aa2325, 0x473ea0, 0x1, ...)
  15. /usr/local/go/src/net/ipsock_posix.go:160 +0x141
  16. net.dialTCP(0x3050e8, 0x3, 0x0, 0xc8295755c0, 0xece412272, 0xc833aa2325, 0x473ea0, 0x2, 0x0, 0x0)
  17. /usr/local/go/src/net/tcpsock_posix.go:171 +0x11e
  18. net.dialSingle(0xc829580b80, 0x1714ea8, 0xc8295755c0, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, 0x0, 0x0)
  19. /usr/local/go/src/net/dial.go:364 +0x3f5
  20. net.dialSerial.func1(0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, 0x0, 0x0)
  21. /usr/local/go/src/net/dial.go:336 +0x75
  22. net.dial(0x3050e8, 0x3, 0x1714ea8, 0xc8295755c0, 0xc8232f96e8, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, ...)
  23. /usr/local/go/src/net/fd_unix.go:40 +0x60
  24. net.dialSerial(0xc829580b80, 0xc829572f00, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0)
  25. /usr/local/go/src/net/dial.go:338 +0x760
  26. net.(*Dialer).Dial(0xc8200783c0, 0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  27. /usr/local/go/src/net/dial.go:232 +0x50f
  28. net.(*Dialer).Dial-fm(0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  29. /usr/local/go/src/net/http/transport.go:38 +0x6e
  30. net/http.(*Transport).dial(0xc820092090, 0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  31. /usr/local/go/src/net/http/transport.go:499 +0x79
  32. net/http.(*Transport).dialConn(0xc820092090, 0x0, 0x7fff5fbff92a, 0x4, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0)
  33. /usr/local/go/src/net/http/transport.go:596 +0x19a9
  34. net/http.(*Transport).getConn.func4(0xc820092090, 0x0, 0x7fff5fbff92a, 0x4, 0xc823166ed0, 0x10, 0xc8232a9560)
  35. /usr/local/go/src/net/http/transport.go:549 +0x66
  36. created by net/http.(*Transport).getConn
  37. /usr/local/go/src/net/http/transport.go:551 +0x265

源代码:

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "os"
  7. "strconv"
  8. "time"
  9. )
  10. func golanggo(url string, round int, c chan int64) {
  11. for i := 0; i < round; i++ {
  12. call(url, c)
  13. }
  14. }
  15. func call(url string, c chan int64) {
  16. eslap := int64(0)
  17. defer func() {
  18. c <- eslap
  19. //fmt.Println("put", eslap)
  20. // if err := recover(); err != nil {
  21. // fmt.Println(err)
  22. // }
  23. }()
  24. now := time.Now()
  25. resp, err := http.Get(url)
  26. defer resp.Body.Close()
  27. if err != nil {
  28. fmt.Println("err:", err)
  29. return
  30. }
  31. if resp.StatusCode == 200 {
  32. ioutil.ReadAll(resp.Body)
  33. //fmt.Println(string(data[:]))
  34. }
  35. eslap = time.Now().Sub(now).Nanoseconds()
  36. }
  37. func main() {
  38. url := os.Args[1]
  39. size, _ := strconv.Atoi(os.Args[2])
  40. round, _ := strconv.Atoi(os.Args[3])
  41. c := make(chan int64)
  42. for i := 0; i < size; i++ {
  43. go golanggo(url, round, c)
  44. }
  45. var total int64 = 0
  46. var nanos int64
  47. for i := 0; i < (size * round); i++ {
  48. //fmt.Print(i)
  49. nanos = <-c
  50. //fmt.Println(i, "get", nanos)
  51. total += nanos
  52. }
  53. fmt.Println(total / 1000000)
  54. }

当执行 go run client.go http://www.baidu.com 10000 1 时,几秒钟后程序崩溃。
当执行 go run client.go http://www.baidu.com 100 1 时,一切正常。

多少个 goroutine 会导致这个错误?

请帮助我!谢谢。

英文:

error message:

  1. goroutine 11357 [runnable]:
  2. net.runtime_pollWait(0x1737f28, 0x77, 0x4fa90)
  3. /usr/local/go/src/runtime/netpoll.go:157 +0x60
  4. net.(*pollDesc).Wait(0xc829571bf0, 0x77, 0x0, 0x0)
  5. /usr/local/go/src/net/fd_poll_runtime.go:73 +0x3a
  6. net.(*pollDesc).WaitWrite(0xc829571bf0, 0x0, 0x0)
  7. /usr/local/go/src/net/fd_poll_runtime.go:82 +0x36
  8. net.(*netFD).connect(0xc829571b90, 0x0, 0x0, 0x1714f80, 0xc829572f20, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0)
  9. /usr/local/go/src/net/fd_unix.go:114 +0x1f6
  10. net.(*netFD).dial(0xc829571b90, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0)
  11. /usr/local/go/src/net/sock_posix.go:137 +0x351
  12. net.socket(0x3050e8, 0x3, 0x2, 0x1, 0x0, 0xc829575500, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, ...)
  13. /usr/local/go/src/net/sock_posix.go:89 +0x411
  14. net.internetSocket(0x3050e8, 0x3, 0x1714f38, 0x0, 0x1714f38, 0xc8295755c0, 0xece412272, 0xc833aa2325, 0x473ea0, 0x1, ...)
  15. /usr/local/go/src/net/ipsock_posix.go:160 +0x141
  16. net.dialTCP(0x3050e8, 0x3, 0x0, 0xc8295755c0, 0xece412272, 0xc833aa2325, 0x473ea0, 0x2, 0x0, 0x0)
  17. /usr/local/go/src/net/tcpsock_posix.go:171 +0x11e
  18. net.dialSingle(0xc829580b80, 0x1714ea8, 0xc8295755c0, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, 0x0, 0x0)
  19. /usr/local/go/src/net/dial.go:364 +0x3f5
  20. net.dialSerial.func1(0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, 0x0, 0x0)
  21. /usr/local/go/src/net/dial.go:336 +0x75
  22. net.dial(0x3050e8, 0x3, 0x1714ea8, 0xc8295755c0, 0xc8232f96e8, 0xece412272, 0x33aa2325, 0x473ea0, 0x0, 0x0, ...)
  23. /usr/local/go/src/net/fd_unix.go:40 +0x60
  24. net.dialSerial(0xc829580b80, 0xc829572f00, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0)
  25. /usr/local/go/src/net/dial.go:338 +0x760
  26. net.(*Dialer).Dial(0xc8200783c0, 0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  27. /usr/local/go/src/net/dial.go:232 +0x50f
  28. net.(*Dialer).Dial-fm(0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  29. /usr/local/go/src/net/http/transport.go:38 +0x6e
  30. net/http.(*Transport).dial(0xc820092090, 0x3050e8, 0x3, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0, 0x0)
  31. /usr/local/go/src/net/http/transport.go:499 +0x79
  32. net/http.(*Transport).dialConn(0xc820092090, 0x0, 0x7fff5fbff92a, 0x4, 0xc823166ed0, 0x10, 0x0, 0x0, 0x0)
  33. /usr/local/go/src/net/http/transport.go:596 +0x19a9
  34. net/http.(*Transport).getConn.func4(0xc820092090, 0x0, 0x7fff5fbff92a, 0x4, 0xc823166ed0, 0x10, 0xc8232a9560)
  35. /usr/local/go/src/net/http/transport.go:549 +0x66
  36. created by net/http.(*Transport).getConn
  37. /usr/local/go/src/net/http/transport.go:551 +0x265

source

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;io/ioutil&quot;
  5. &quot;net/http&quot;
  6. &quot;os&quot;
  7. &quot;strconv&quot;
  8. &quot;time&quot;
  9. )
  10. func golanggo(url string, round int, c chan int64) {
  11. for i := 0; i &lt; round; i++ {
  12. call(url, c)
  13. }
  14. }
  15. func call(url string, c chan int64) {
  16. eslap := int64(0)
  17. defer func() {
  18. c &lt;- eslap
  19. //fmt.Println(&quot;put&quot;, eslap)
  20. // if err := recover(); err != nil {
  21. // fmt.Println(err)
  22. // }
  23. }()
  24. now := time.Now()
  25. resp, err := http.Get(url)
  26. defer resp.Body.Close()
  27. if err != nil {
  28. fmt.Println(&quot;err:&quot;, err)
  29. return
  30. }
  31. if resp.StatusCode == 200 {
  32. ioutil.ReadAll(resp.Body)
  33. //fmt.Println(string(data[:]))
  34. }
  35. eslap = time.Now().Sub(now).Nanoseconds()
  36. }
  37. func main() {
  38. url := os.Args[1]
  39. size, _ := strconv.Atoi(os.Args[2])
  40. round, _ := strconv.Atoi(os.Args[3])
  41. c := make(chan int64)
  42. for i := 0; i &lt; size; i++ {
  43. go golanggo(url, round, c)
  44. }
  45. var total int64 = 0
  46. var nanos int64
  47. for i := 0; i &lt; (size * round); i++ {
  48. //fmt.Print(i)
  49. nanos = &lt;-c
  50. //fmt.Println(i, &quot;get&quot;, nanos)
  51. total += nanos
  52. }
  53. fmt.Println(total / 1000000)
  54. }

when exec go run client.go http://www.baidu.com 10000 1, and after a few seconds program crash.
when exec go run client.go http://www.baidu.com 100 1, it's ok.

How much of goroutine will cause this error?

Please help me! Thanks.

答案1

得分: 5

resp, err := http.Get(url)
defer resp.Body.Close()
if err != nil {
fmt.Println("err:", err)
return
}
如果err不等于nil,则resp等于nil,因此会出现空指针解引用崩溃。
请使用以下代码修复:

resp, err := http.Get(url)
if err != nil {
fmt.Println("err:", err)
return
}
defer resp.Body.Close()

英文:
  1. resp, err := http.Get(url)
  2. defer resp.Body.Close()
  3. if err != nil {
  4. fmt.Println(&quot;err:&quot;, err)
  5. return
  6. }

If err!= nil, then resp==nil, so crash with nil pointer dereference.
Fix ur code with:

  1. resp, err := http.Get(url)
  2. if err != nil {
  3. fmt.Println(&quot;err:&quot;, err)
  4. return
  5. }
  6. defer resp.Body.Close()

答案2

得分: 0

你可能因为使用系统(基于cgo)解析同时的主机名解析而达到了单个Go进程的操作系统线程限制。为了使用纯Go解析,它不会为每个解析请求占用一个系统线程,尝试设置GOBEBUG环境变量,像这样export GODEBUG=netdns=go(参见https://golang.org/pkg/net文档的“Name Resolution”部分)。

单个Go进程的默认操作系统线程限制设置为10000:https://golang.org/pkg/runtime/debug/#SetMaxThreads

此外,似乎您正在运行最新的Go运行时,默认情况下会输出单个goroutine的跟踪;设置GOTRACEBACK=all环境变量将为您提供更大的堆栈跟踪 - 最好将其完整地发布出来。

英文:

You probably hit os thread limit for single go process due to simultaneous hostname resolving using system (cgo-based) resolving. For using pure-go resolving which does not occupy one system thread per resolve request, try setting GOBEBUG environment variable like this export GODEBUG=netdns=go (see https://golang.org/pkg/net doc, "Name Resolution" section).

The default os thread limit for single Go process is set to 10000: https://golang.org/pkg/runtime/debug/#SetMaxThreads

Also it seems that you're running latest Go runtime which outputs trace of a single goroutine by default; running with GOTRACEBACK=all environment variable set will give you much bigger stacktrace — it's always better to post it in full.

huangapple
  • 本文由 发表于 2016年2月1日 18:40:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/35128427.html
匿名

发表评论

匿名网友

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

确定