go - 从 api 同时请求数据时 TLS 握手超时

标签 go concurrency

这是我第一个使用并发的程序,所以我可能遗漏了一些相当简单的东西。

package main

import(
    "net/http"
    "net/url"
    "log"
    "flag"
    "io/ioutil"
    "fmt"
    "golang.org/x/net/html"
    "strings"
    "encoding/json"
    "os"
    "html/template"
)

type fileInfo struct{
    Title string `json:"Title"`;
    Year string `json:"Year"`;
    Runtime string `json:"Runtime"`
    Genre string `json:"Genre"` 
    Rating string `json:"imdbRating"`;
    Description string `json:"Plot"`;
    Image string `json:"Poster"`;
    Awards string `json:"Awards"`;
}

var movie struct{
    Name string;
    Year string;
}
var Movies []fileInfo
func main() {
    flag.Parse()
    files, _ := ioutil.ReadDir(flag.Args()[0])
    var queryNames []string
    for _, f := range files {
        go func(){
            queryNames= append(queryNames,url.QueryEscape(f.Name()))
        }()
    }
    //fmt.Println(os.Getenv("GOPATH") + "/src/github.com/krashcan/review/template/index.tpl")
    fmt.Println("Preparing data")


    for _, f := range queryNames {
        go GetTitleAndYear("https://opensubtitles.co/search?q=" + f)
    }




    fmt.Println("Done")
    http.HandleFunc("/",ShowRatings)
    http.Handle("/static/",http.StripPrefix("/static/",http.FileServer(http.Dir(os.Getenv("GOPATH") + "/src/github.com/krashcan/review/static"))))

    log.Fatal(http.ListenAndServe(":8080",nil))
}

func ShowRatings(w http.ResponseWriter,r *http.Request){
    t,err := template.ParseFiles(os.Getenv("GOPATH") + "/src/github.com/krashcan/review/template/index.tpl")
    if(err!=nil){
        log.Fatal(err)
    }
    t.Execute(w,Movies)
}

func GetTitleAndYear(url string){
    resp,err := http.Get(url)
    if err!=nil{
        log.Fatal(err)
    }
    var movieData string
    if resp.StatusCode != 200 {
        fmt.Println("statuscode",err)
    }
    z := html.NewTokenizer(resp.Body)
    for{
        tt := z.Next()

        if tt == html.ErrorToken{
            return
        }else if tt==html.StartTagToken{
            t:= z.Token()
            if t.Data=="h4"{
                tt = z.Next()
                tt = z.Next()
                tt = z.Next()
                t = z.Token()
                movieData = strings.TrimSpace(t.Data)               
                break
            }
        }
    }

    movie.Name = movieData[:len(movieData)-6]
    movie.Year = movieData[len(movieData)-5:len(movieData)-1]
    movie.Name = strings.Replace(movie.Name, " ", "+", -1)
    url = "http://www.omdbapi.com/?t=" + movie.Name + "&y=" + movie.Year + "&plot=short&r=json"  
    req,err := http.Get(url)

    if err!=nil{
        log.Fatal(err)
    }
    var x fileInfo
    jsonParser := json.NewDecoder(req.Body)
    if err := jsonParser.Decode(&x); err != nil {
        log.Fatal("parsing config file", err)
    }
    Movies = append(Movies,x)
    fmt.Println(x.Title,x.Year)     
}

这个程序第一次完美运行。但在那之后,它继续为随机文件名提供 net/http:TLS Handshake timeout。我不确定是什么原因造成的。可能的解决方案是什么?另外这个错误到底是什么?

编辑 2:为了解决并发竞争问题,我使用了 channel ,但现在我的程序与以前相比非常慢。我更新的主要功能:

func main() {
    flag.Parse()
    files, _ := ioutil.ReadDir(flag.Args()[0])
    var queryNames []string
    for _, f := range files {
        queryNames= append(queryNames,url.QueryEscape(f.Name()))
    }
    //fmt.Println(os.Getenv("GOPATH") + "/src/github.com/krashcan/review/template/index.tpl")
    fmt.Println("Preparing data")
    ch := make(chan string)
    done := make(chan bool)
    go func(){
        for{
            name,more := <-ch
            if more{
                GetTitleAndYear("https://opensubtitles.co/search?q=" + name)
            }else{
                done <-true
            }
        }
    }()

    for i:=0;i<len(queryNames);i++{
        ch <- queryNames[i] 
    }
    <- done
    fmt.Println("Preparation DONE")
    http.HandleFunc("/",ShowRatings)
    http.Handle("/static/",http.StripPrefix("/static/",http.FileServer(http.Dir(os.Getenv("GOPATH") + "/src/github.com/krashcan/review/static"))))

    log.Fatal(http.ListenAndServe(":8080",nil))
}

请建议我一种方法,既能保持与以前相同的速度,又能避免绕过问题。

编辑 1:我添加了完整的程序。无法描述堆栈溢出时的行号,我只在 main 函数中使用了并发。如果您觉得需要对我编写 go 程序的方式提出建议,请这样做,我是初学者,我很乐意做正确的事情。

最佳答案

net/http发生在客户端有大量http.Get()请求时。为避免 TLS 握手超时错误

t := &http.Transport{
            Dial: (&net.Dialer{
                    Timeout: 60 * time.Second,
                    KeepAlive: 30 * time.Second,
            }).Dial,
            // We use ABSURDLY large keys, and should probably not.
            TLSHandshakeTimeout: 60 * time.Second,
    }
    c := &http.Client{
            Transport: t,
    }
    resp, err := c.Get("https://internal.lan/")

找到了 here

关于go - 从 api 同时请求数据时 TLS 握手超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41719797/

相关文章:

java - 尝试在 Go 中实现 Java Guava sets.difference

java - 如何在java中启动三个按顺序运行的任务?

multithreading - 添加额外的内核或 CPU 根本不会提高性能的点在哪里?

java - volatile 实际上是如何工作的?

c++ - 为什么添加线程不能带来进一步的性能提升

Python 队列的使用适用于线程,但(显然)不适用于多处理

go - DEX LDAP 连接器 token 签名

go - nil不会将数据库记录设置为NULL

node.js - cc1.exe : sorry, 未实现:64 位模式未在退出状态 2 退出状态 1 中编译

file - 如何检查Go中是否存在文件?