使用渠道转移管道

时间:2015-11-27 13:29:26

标签: go

我正在探索Go并试图使用频道设置一种管道。我只想读取main()中的内容并将它们发送到process()进行处理,在这种情况下只需将值打印到屏幕上。

不幸的是,在下面的代码中,似乎process()从不从频道中读取,或者至少它没有打印任何东西;我做错了什么?

package main

import ( "fmt" ; "database/sql" ; _ "github.com/lib/pq" ; "time" ; "gopkg.in/redis.v3" )//; "strconv" )

type Record struct {
    userId, myDate int
    prodUrl string
}


func main(){

    //connect to db
    db, err := sql.Open(...)
    defer db.Close()

    //error check here...

    //exec query
    rows, err := db.Query("select userID,url,date from mytable limit 10")
    defer rows.Close()

    //error check here...   

    //create channel to buffer rows read
    bufferChan := make(chan *Record,1000)
    go process(bufferChan)

    //iterate through results and send them to process()
    row := new(Record)
    for rows.Next(){
        err := rows.Scan(&row.userId, &row.prodUrl, &row.myDate)        
        bufferChan <- row
        fmt.Printf("row sent %v",row.userId)                    
    }   
}

//prints Record values
func process (buffer chan *Record) {
    row := <- buffer
    fmt.Printf("row received: %d %v %d ", row.userId,row.prodUrl,row.myDate)
}

3 个答案:

答案 0 :(得分:2)

func进程没有打印任何东西的原因是你在for循环之后func主要退出.Next结束从而退出程序。你需要做几件事。

  1. 在for循环后添加对close的调用以指示结束添加消息 缓冲通道否则会导致死锁。所以打电话 close(bufferChan)
  2. 使用范围在func进程中迭代通道。
  3. 传递一个额外的频道进行处理以了解它何时完成 主要可以等到过程结束。
  4. 请查看下面的代码段:

    package main
    
    import "fmt"
    
    func main() {
        bufferChan := make(chan int, 1000)
        done := make(chan bool)
        go process(bufferChan, done)
        for i := 0; i < 100; i++ {
            bufferChan <- i
        }
        close(bufferChan)
    
        select {
        case <-done:
            fmt.Println("Done")
        }
    
    }
    
    func process(c chan int, done chan bool) {
        for s := range c {
            fmt.Println(s)
        }   
        done <- true
    
    }
    

答案 1 :(得分:1)

您的主要功能退出,因此整个程序结束。它应该等待处理结束。此外,进程函数应该使用范围关键字循环遍历通道。

工作解决方案的脚手架看起来像这样:

package main

import "fmt"

func process(input chan int, done chan struct{}) {
    for i := range input {
        fmt.Println(i)
    }
    done <- struct{}{}
}

func main() {
    input := make(chan int)
    done := make(chan struct{})

    go process(input, done)

    for i := 1; i < 10; i++ {
        input <- i
    }
    close(input)

    <-done
}

Playground

答案 2 :(得分:1)

我相信您正在寻找io.pipe() go API,它会在编写者和读者之间创建同步内存管道。这里没有缓冲。它可用于连接期望io.Reader的代码与期望io.Writer的代码。

在您的情况下,io.PipeWriter是代码&#34;从数据库读取值&#34;和&#34; io.PipeReader&#34;是代码&#34;将值写入屏幕&#34;。

这里是没有任何缓冲区的流数据的示例,即bytes.Buffer

// Set up the pipe to write data directly into the Reader.
pr, pw := io.Pipe()
// Write JSON-encoded data to the Writer end of the pipe.
// Write in a separate concurrent goroutine, and remember
// to Close the PipeWriter, to signal to the paired PipeReader
// that we’re done writing.
go func() {
  err := json.NewEncoder(pw).Encode(&v)
  pw.Close()
}()
// Send the HTTP request. Whatever is read from the Reader
// will be sent in the request body.
// As data is written to the Writer, it will be available
// to read from the Reader.
resp, err := http.Post(“example.com”, “application/json”, pr)

参考:

https://medium.com/stupid-gopher-tricks/streaming-data-in-go-without-buffering-3285ddd2a1e5