为了账号安全,请及时绑定邮箱和手机立即绑定

Goroutines 破坏了程序

Goroutines 破坏了程序

Go
慕慕森 2021-06-08 17:00:01
问题是:有一个网络服务器。我认为在页面加载中使用 goroutines 是有益的,所以我继续这样做:将 loadPage 函数称为 goroutine。但是,在执行此操作时,服务器只会停止工作而不会出错。它会打印一张空白的白页。问题必须出在函数本身 - 不知何故与 goroutine 存在冲突。这些是相关的功能:func loadPage(w http.ResponseWriter, path string) {   s := GetFileContent(path)   w.Header().Add("Content-Type", getHeader(path))   w.Header().Add("Content-Length", GetContentLength(path))   fmt.Fprint(w, s)}func GetFileContent(path string) string {   cont, err := ioutil.ReadFile(path)   e(err)   aob := len(cont)   s := string(cont[:aob])   return s}func GetFileContent(path string) string {   cont, err := ioutil.ReadFile(path)   e(err)   aob := len(cont)   s := string(cont[:aob])   return s}func getHeader(path string) string {   images := []string{".jpg", ".jpeg", ".gif", ".png"}   readable := []string{".htm", ".html", ".php", ".asp", ".js", ".css"}   if ArrayContainsSuffix(images, path) {      return "image/jpeg"   }   if ArrayContainsSuffix(readable, path) {      return "text/html"   }   return "file/downloadable"}func ArrayContainsSuffix(arr []string, c string) bool {   length := len(arr)   for i := 0; i < length; i++ {      s := arr[i]      if strings.HasSuffix(c, s) {         return true      }   }return false}
查看完整描述

2 回答

?
呼如林

TA贡献1798条经验 获得超3个赞

之所以出现这种情况的原因是因为你的HandlerFunc其称之为“loadPage”与请求同步调用。当您在 go 例程中调用它时,处理程序实际上是立即返回,从而立即发送响应。这就是为什么你会得到一个空白页。


您可以在server.go 中看到这一点(第 1096 行):


serverHandler{c.server}.ServeHTTP(w, w.req)

if c.hijacked() {

    return

}

w.finishRequest()

该ServeHTTP函数调用您的处理程序,并在返回后立即调用“finishRequest”。因此,只要您的 Handler 函数想要满足请求,它就必须阻塞。


使用 go 例程实际上不会使您的页面更快。正如 Philip 建议的那样,将单个 go 例程与通道同步,在这种情况下也无济于事,因为这与根本没有 go 例程相同。


您的问题的根源实际上是ioutil.ReadFile,它在发送之前将整个文件缓冲到内存中。


如果要流式传输文件,则需要使用os.Open. 您可以使用io.Copy将文件内容流式传输到浏览器,浏览器将使用分块编码。


这看起来像这样:


f, err := os.Open(path)

if err != nil {

    http.Error(w, "Not Found", http.StatusNotFound)

    return

}

n, err := io.Copy(w, f)

if n == 0 && err != nil {

    http.Error(w, "Error", http.StatusInternalServerError)

    return

}

如果由于某种原因您需要在多个 go 例程中工作,请查看sync.WaitGroup. 渠道也可以工作。


如果您只想提供一个文件,则还有其他为此进行了优化的选项,例如FileServer或ServeFile。


查看完整回答
反对 回复 2021-06-21
  • 2 回答
  • 0 关注
  • 178 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信