猿问

为什么第二个通道没有从前一个通道接收数据

我正在使用 go 通道做我的第一步,并尝试编写下面的代码,我想使用从给定 csv 文件读取的 goroutine 执行以下操作,将读取记录发送到另一个添加相同记录的通道到另一个 csv 文件:


package main


import (

    "encoding/csv"

    "encoding/json"

    "fmt"

    "log"

    "os"

)


func failOnError(err error) {

    if err != nil {

        log.Fatal("Error:", err)

        panic(err)

    }

}

func main() {

    read := make(chan Data)

    go func(input_file string) {

        var data Data


        fr, err := os.Open(input_file)

        failOnError(err)

        defer fr.Close()

        r := csv.NewReader(fr)

        rows, err := r.ReadAll()

        failOnError(err)

        data.header = rows[0]

        for _, row := range rows[1:] {

            data.lines = append(data.lines, Person{

                Firstname: row[0],

                Lastname:  row[1],

                Address: &Address{

                    City:  row[2],

                    State: row[3],

                },

            })

        }


        peopleJson, _ := json.Marshal(data.lines)

        fmt.Println(string(peopleJson))   // This is working smoothly


        read <- data

    }("people.csv")


    csvOut, err := os.Create("resultsfile.csv")

    if err != nil {

        log.Fatal("Unable to open output")

    }


    out := make(chan int)

    select {

    case data := <-read:

        go func(data Data) {

            println("data received")     // <-- Not show up

            w := csv.NewWriter(csvOut)

            defer csvOut.Close()

            // handle header

            data.header = append(data.header, "score")

            if err = w.Write(data.header); err != nil {

                log.Fatal(err)

            }

            /*

                hanlde data

            */

            w.Flush()

            out <- 0

        }(data)

    case _ = <-out:

        println("done")

    }


}


type Person struct {

    Firstname string   `json:"firstname"` // JSON annotation will allow for easy printing to JSON after it had been loaded

    Lastname  string   `json:"lastname"`

    Address   *Address `json:"address,omitempty"`

}



德玛西亚99
浏览 124回答 1
1回答

慕姐8265434

问题是这样的:&nbsp; &nbsp; select {&nbsp; &nbsp; case data := <-read:&nbsp; &nbsp; &nbsp; &nbsp; go func(data Data) {这select是main函数中的最后一件事。当它从 读取data时read,它会在后台启动一个 goroutine 来处理它。然后main函数结束,程序退出。Go 不会自动等待 goroutines。您可以使用“完成”通道或其他任何方式在它们之间进行同步。你基本上有一个在概念上看起来像这样的管道:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;----> process -> write to `out`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /start --> main file waits&nbsp; data on `read` *or* wait for `out` -> done&nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; ---> CSV reads all lines and outputs data to `read`&nbsp;&nbsp;因为您实际上只通过频道发送一条消息,所以您实际上并不需要 aselect或 a loop。你只需要等待数据,处理它,然后main等待完成:package mainimport (&nbsp; &nbsp; "encoding/csv"&nbsp; &nbsp; "encoding/json"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "os")func failOnError(err error) {&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal("Error:", err)&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; read := make(chan Data)&nbsp; &nbsp; go func(input_file string) {&nbsp; &nbsp; &nbsp; &nbsp; var data Data&nbsp; &nbsp; &nbsp; &nbsp; fr, err := os.Open(input_file)&nbsp; &nbsp; &nbsp; &nbsp; failOnError(err)&nbsp; &nbsp; &nbsp; &nbsp; defer fr.Close()&nbsp; &nbsp; &nbsp; &nbsp; r := csv.NewReader(fr)&nbsp; &nbsp; &nbsp; &nbsp; rows, err := r.ReadAll()&nbsp; &nbsp; &nbsp; &nbsp; failOnError(err)&nbsp; &nbsp; &nbsp; &nbsp; data.header = rows[0]&nbsp; &nbsp; &nbsp; &nbsp; for _, row := range rows[1:] {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.lines = append(data.lines, Person{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Firstname: row[0],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Lastname:&nbsp; row[1],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Address: &Address{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; City:&nbsp; row[2],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; State: row[3],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; peopleJson, _ := json.Marshal(data.lines)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(string(peopleJson)) // This is working smoothly&nbsp; &nbsp; &nbsp; &nbsp; read <- data&nbsp; &nbsp; }("people.csv")&nbsp; &nbsp; csvOut, err := os.Create("resultsfile.csv")&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal("Unable to open output")&nbsp; &nbsp; }&nbsp; &nbsp; out := make(chan int)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; data := <-read&nbsp; &nbsp; &nbsp; &nbsp; println("data received") // <-- Not show up&nbsp; &nbsp; &nbsp; &nbsp; w := csv.NewWriter(csvOut)&nbsp; &nbsp; &nbsp; &nbsp; defer csvOut.Close()&nbsp; &nbsp; &nbsp; &nbsp; // handle header&nbsp; &nbsp; &nbsp; &nbsp; data.header = append(data.header, "score")&nbsp; &nbsp; &nbsp; &nbsp; if err = w.Write(data.header); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hanlde data&nbsp; &nbsp; &nbsp; &nbsp; */&nbsp; &nbsp; &nbsp; &nbsp; w.Flush()&nbsp; &nbsp; &nbsp; &nbsp; out <- 0&nbsp; &nbsp; }()&nbsp; &nbsp; <-out&nbsp; &nbsp; println("done")}type Person struct {&nbsp; &nbsp; Firstname string&nbsp; &nbsp;`json:"firstname"` // JSON annotation will allow for easy printing to JSON after it had been loaded&nbsp; &nbsp; Lastname&nbsp; string&nbsp; &nbsp;`json:"lastname"`&nbsp; &nbsp; Address&nbsp; &nbsp;*Address `json:"address,omitempty"`}type Address struct {&nbsp; &nbsp; City&nbsp; string `json:"city"`&nbsp; &nbsp; State string `json:"state"`}type Data struct {&nbsp; &nbsp; header []string&nbsp; &nbsp; lines&nbsp; []Person}OP问,有没有办法在没有选择的情况下从以前的频道接收输入,同时确保程序在完成所需内容之前不退出?– Hasan A Yousef 1 分钟前您所写的所有频道都只传递一条消息,这意味着一旦您阅读了该频道一次,您就可以假设作者是完整的。因此,通过使用out渠道,您已经实现了这一点。如果您有未知数量的发送到通道,您可以使用内置close功能来实现此目的:package mainimport (&nbsp; "fmt")func main() {&nbsp; send := make(chan int)&nbsp; result := make(chan int)&nbsp; go func() {&nbsp; &nbsp; sum := 0&nbsp; &nbsp; for i := range send {&nbsp; &nbsp; &nbsp; sum += i&nbsp; &nbsp; }&nbsp; &nbsp; result <- sum&nbsp; }()&nbsp; for _, x := range []int{1,2,3}&nbsp; {&nbsp; &nbsp; send <- x&nbsp; }&nbsp; close(send)&nbsp; fmt.Println("Sum is: ", <-result)}
随时随地看视频慕课网APP

相关分类

Go
我要回答