如何从一个io.Reader拥有多个使用者?

问题描述 投票:2回答:2

我正在使用bufio.Scannerhttp.Request以及go例程来并行计算单词和行的小脚本。

package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net/http"
    "time"
)

func main() {
    err := request("http://www.google.com")

    if err != nil {
        log.Fatal(err)
    }

    // just keep main alive with sleep for now
    time.Sleep(2 * time.Second)
}

func request(url string) error {
    res, err := http.Get(url)

    if err != nil {
        return err
    }

    go scanLineWise(res.Body)
    go scanWordWise(res.Body)

    return err
}

func scanLineWise(r io.Reader) {
    s := bufio.NewScanner(r)
    s.Split(bufio.ScanLines)

    i := 0

    for s.Scan() {
        i++
    }

    fmt.Printf("Counted %d lines.\n", i)
}

func scanWordWise(r io.Reader) {
    s := bufio.NewScanner(r)
    s.Split(bufio.ScanWords)

    i := 0

    for s.Scan() {
        i++
    }

    fmt.Printf("Counted %d words.\n", i)
}

Source

与流scanLineWise或多或少地期望一样,scalWordWise将计数一个数字。这是因为scanLineWise已从req.Body读取所有内容。

我想知道:如何优雅地解决这个问题?

我首先想到的是构建一个实现io.Readerio.Writer的结构。我们可以使用io.Copy来读取req.Body并将其写入writer。当扫描仪从该写入器读取数据时,写入器将复制数据而不是读取数据。不幸的是,随着时间的流逝,这只会收集内存并破坏整个流的想法。

我正在研究一个小的脚本,该脚本使用bufio.Scanner和http.Request以及go例程来并行计算单词和行数。包主要导入(“ bufio”“ fmt”“ io”“ log” ...

stream go
2个回答
18
投票

这些选项非常简单-您可以维护数据的“流”,也可以缓冲主体。

如果您确实确实需要阅读更多的内容,然后顺序阅读一次,则需要将其缓冲在某个地方。无法解决。


5
投票

您可以使用通道,在scanLineWise中进行实际读数,然后将行传递到scanWordWise,以获取example

© www.soinside.com 2019 - 2024. All rights reserved.