去频道:如何使这种非阻塞?

时间:2015-05-01 08:52:54

标签: go channel

我有一个脚本,它从数据库中选择一些数据并将其发送到要由多个goroutine处理的通道,然后将结果发送回主线程以在数据库上更新。

然而,在将数据发送到第一个频道时,它正在挂起(可能阻塞)。

通过以下方式全局创建频道:

var chin = make(chan in)
var chout = make(chan out)

inout都是structs

首先启动goroutines:

for i:=0; i<5; i++ {
     go worker()
}

加载频道的代码是:

        if verbose {
            fmt.Println(`Getting nextbatch2 and sending to workers`)
        }

        rows, err = nextbatch2.Query()
        if err != nil {
            panic(err)
        }

        var numtodo int
        for rows.Next() {
            err = rows.Scan(&id, &data)
            if err != nil {
                rows.Close()
                panic(err)
            }

            // Start
            var vin in
            vin.id = id
            vin.data = data
            chin <- vin
            numtodo++
        }
        rows.Close()

然后立即:

        if verbose {
            fmt.Println(`Processing out channel from workers`)
        }

        for res := range chout {
            update5.Exec(res.data, res.id)
            if numtodo--; numtodo == 0 {
                break
            }
        }

在后台运行多个worker() goroutines:

func worker() {
      for res := range chin {
            var v out
            v.id = res.id
            v.data = process(res.data)
            chout <- v
      }
}

此代码在打印Getting nextbatch2 and sending to workers后挂起。它永远不会到达Processing out channel from workers。所以它挂在rows.Next()循环中的某个地方,因为chin通道应该是非阻塞的,我无法弄清楚原因 - 即使worker() goroutines没有处理它至少应该完成那个循环。

有什么想法吗?

修改

通过在fmt.Println(" on", numtodo)循环的末尾添加rows.Next(),我可以看到它在5之后阻塞,我不明白,因为它应该是非阻塞的,对吧?

编辑2:

通过将频道更改为make(chan in/out, 100),它现在将在105后阻止。

1 个答案:

答案 0 :(得分:2)

  

接收器始终阻塞,直到有数据要接收为止。如果通道未缓冲,则发送方将阻塞,直到接收方收到该值。

https://golang.org/doc/effective_go.html#channels

因此,您可以将您的消费者代码重写为:

(NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String)!

您还需要go func(){ for res := range chout { update5.Exec(res.data, res.id) } }() close(chin)才能正确使用close(chout)声明。