2017-01-14 10 views
0

私はいくつかのファイルの中にそれらを格納するためのURLのリストを取得する簡単なプログラムを書いています。この例では、GoogleとGmailがあります。私はいつも同じソフトウェアを異なるバージョンで実行します。プログラムはgoFetchAllの内部に格納されます:これはアルゴリズムのコンパイルされたバージョンの名前です。なぜ `nbytes、err:= io.Copy(ioutil.Discard、resp.Body)`は常に0を返しますか?

0.23s  0 http://www.google.com 
1.15s  0 http://www.gmail.com 

を構築して行きます。最新のバージョンは常にカウントなぜ誰かが説明でき

0.25s 10363 http://www.google.com 
0.89s 66576 http://www.gmail.com 
package main 

import (
    "fmt" 
    "io" 
    "io/ioutil" 
    "net/http" 
    "os" 
    "time" 
) 

func main() { 
    start := time.Now() 

    ch := make(chan string) 

    for _, url := range os.Args[1:] { 
     go fetch(url, ch) 
    } 

    for range os.Args[1:] { 
     fmt.Println(<-ch) 
    } 

    fmt.Println("%.2fs elapsed\n", time.Since(start).Seconds()) 
} 

func fetch(url string, ch chan<- string) { 
    start := time.Now() 
    resp, err := http.Get(url) 
    if err != nil { 
     ch <- fmt.Sprint(err) 
     return 
    } 

    nbytes, err := io.Copy(ioutil.Discard, resp.Body) 
    resp.Body.Close() 
    if err != nil { 
     ch <- fmt.Sprintf("whioe reading %s: %v", url, err) 
     return 
    } 

    secs := time.Since(start).Seconds() 
    ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url) 
} 

:しかし、それは私も実際に動作する同じスクリプトの古いバージョンをしましたなかれ0

package main 

import (
    "fmt" 
    "io" 
    "io/ioutil" 
    "net/http" 
    "os" 
    "strings" 
    "time" 
) 

func main() { 
    start := time.Now() 

    ch := make(chan string) 

    for _, url := range os.Args[1:] { 
     go fetch(url, ch) 
    } 

    for range os.Args[1:] { 
     fmt.Println(<-ch) 
    } 

    secs := time.Since(start).Seconds() 
    fmt.Sprintf("%.2fs elapsed\n", secs) 
} 

func fetch(url string, ch chan<- string) { 
    start := time.Now() 
    resp, err := http.Get(url) 
    if err != nil { 
     ch <- fmt.Sprint(err) 
     return 
    } 

    body, err := ioutil.ReadAll(resp.Body) 
    if err != nil { 
     ch <- fmt.Sprintf("Cant catch content") 
     return 
    } 

    nbytes, err := io.Copy(ioutil.Discard, resp.Body) 
    defer resp.Body.Close() 
    if err != nil { 
     ch <- fmt.Sprintf("while reading %s: %v", url, err) 
     return 
    } 

    secs := time.Since(start).Seconds() 
    ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url) 

    // store on file 
    filename := string(url) 
    filename = strings.Replace(filename, ":", "", -1) 
    filename = strings.Replace(filename, "//", "-", -1) 
    filename = strings.Replace(filename, "/", "", -1) 
    filename = strings.Replace(filename, ".", "-", -1) 
    filename = "downloads/" + filename + ".html" 

    f, err := os.Create(filename) 
    f.Write(body) 
    defer f.Close() 
    if err != nil { 
     ch <- fmt.Sprintf("while writing %s: %v", url, err) 
     return 
    } 
} 

です0秒か?


私の部分的な解決方法は次のとおりです。あなたは既に一度その呼び出し時の応答を読んだためであるために私は再びhttp.Get(url)

resp, err := http.Get(url) 
nbytes, err := io.Copy(ioutil.Discard, resp.Body) 
defer resp.Body.Close() // dont leak resources 
if err != nil { 
    ch <- fmt.Sprintf("while reading %s: %v", url, err) 
    return 
} 

resp, err = http.Get(url) 
body, err := ioutil.ReadAll(resp.Body) 
if err != nil { 
    ch <- fmt.Sprintf("Cant catch content") 
    return 
} 
+0

コードでは、2番目の数値は 'nbytes'変数です。または、古いスクリプトは実際に実行するのに18.5時間(66576秒)かかりますか? – JJJ

+0

ありがとう、私は新しいタイトルとより良い説明で質問を更新しました。またすみません。 – sensorario

答えて

1

理由を要求してきました。したがって、2回目には、0バイトがストリームから読み込まれます。エラーチェックの呼び出しを除去した後:

resp, err := http.Get(url) 
body, err := ioutil.ReadAll(resp.Body) 
nbytes, err := io.Copy(ioutil.Discard, resp.Body) 

は、2行目ReadAll呼び出しに注意してください。

ストリームを初期化した直後にdeferコールを使用することをお勧めします(実際の質問には関係ありません)。例えば:

resp, err := http.Get(url) 
if err != nil { 
    ch <- fmt.Sprint(err) 
    return 
} 
defer resp.Body.Close() 

は特に言及していないが、それはthis section in Effective Goから推論することができます。

第2に、これは、関数の終わりに配置するよりもはるかに明確な、開いた部分の近くに閉じることを意味します。

+0

うん!!!私は 'nbytes、err:= io.Copy(ioutil.Discard、resp.Body)'と 'body、err:= ioutil.ReadAll(resp.Body)'を逆転しました。良い答えをありがとう! – sensorario

+0

しかし、どうすれば内容を読み込み、バイト数を数えることができますか? – sensorario

+0

完全にはわかりません。 'body'はバイト配列を保持します。あなたは 'len'を使ってその長さを知ることができますが、これはおそらくあなたが望むものではありません。値をチェックしたところ、56の差があり、 'io.Copy'はより高い値を返しました。 – Kashyap

関連する問題