duanju7199 2018-08-27 11:52
浏览 58
已采纳

为什么加工后的协程卡住了?

I am new to Golang. I have been using GORM and concurrency of go to read a SQLite database and write it into a CSV file. It is working smooth but when the processing is done it is not ending the main program and exiting. I have to print command+c to exit. I don't know what I am doing wrong. May be it is entering into some blocking or deadlock mode or something. Moreover it is not printing a bye message too. Which means it is still trying to read the data from the channel. Please help. Here is the code.

package main

import (
    "fmt"
    "reflect"

    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/sqlite"
)

type AirQuality struct {
    // gorm.Model
    // ID      uint   `gorm:"column:id"`
    Index   string `gorm:"column:index"`
    BEN     string `gorm:"column:BEN"`
    CH4     string `gorm:"column:CH4"`
    CO      string `gorm:"column:CO"`
    EBE     string `gorm:"column:EBE"`
    MXY     string `gorm:"column:MXY"`
    NMHC    string `gorm:"column:NMHC"`
    NO      string `gorm:"column:NO"`
    NO2     string `gorm:"column:NO_2"`
    NOX     string `gorm:"column:NOx"`
    OXY     string `gorm:"column:OXY"`
    O3      string `gorm:"column:O_3"`
    PM10    string `gorm:"column:PM10"`
    PM25    string `gorm:"column:PM25"`
    PXY     string `gorm:"column:PXY"`
    SO2     string `gorm:"column:SO_2"`
    TCH     string `gorm:"column:TCH"`
    TOL     string `gorm:"column:TOL"`
    Time    string `gorm:"column:date; type:timestamp"`
    Station string `gorm:"column:station"`
}

func (AirQuality) TableName() string {
    return "AQ"
}

func main() {
    c := generateRows("boring!!")
    for {
        fmt.Println(<-c)
        if c == nil {
            fmt.Println("Bye")
            break
        }
    }
}

func generateRows(msg string) <-chan []string {
    c := make(chan []string)
    go func() {
        db, err := gorm.Open("sqlite3", "./load_testing_7.6m.db")
        if err != nil {
            panic("failed to connect database")
        }
        defer db.Close()
        rows, err := db.Model(&AirQuality{}).Limit(20).Rows()
        defer rows.Close()
        if err != nil {
            panic(err)
        }
        for rows.Next() {
            var aq AirQuality
            db.ScanRows(rows, &aq)
            v := reflect.Indirect(reflect.ValueOf(aq))
            var buf []string
            for i := 0; i < v.NumField(); i++ {
                buf = append(buf, v.Field(i).String())
            }
            c <- buf
        }
    }()
    return c
}
  • 写回答

1条回答 默认 最新

  • duan1396 2018-08-27 11:57
    关注

    Receiving from an unbuffered channel (such as yours) where no one is ready to send a value blocks. This is what you experience. Spec: Receive operator:

    The expression [<-c] blocks until a value is available.

    The common way to signal "EOF" in case of channels is to close the channel from the sender's side when there are no more values to send, using the builtin close() function.

    Attempting to receive from a closed channel can proceed immediately, yielding the zero value of the element type of the channel. To detect this "closed" state, use the special comma-ok idiom:

    value, ok := <- c
    

    If the channel is closed, ok will be false (otherwise it's true).

    The easy and proper way to "drain" a channel until it is closed is to use the for range loop, like this:

    for value := range c {
        fmt.Println("Received:", value)
    }
    

    The for range terminates once all values have been received from channel c that were sent on it before it was closed.

    So inside generateRows(), do this:

    go func() {
        // // Use defer so it will be closed no matter how this function call ends
        defer close(c)
        // ...
    }()
    

    And your main():

    func main() {
        c := generateRows("boring!!")
        for v := range c {
            fmt.Println(v)
        }
        fmt.Println("Bye")
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?