dongmu1989 2017-06-01 11:59 采纳率: 0%
浏览 53

Golang频道处理send!= receive

Consider the toy example below. The code works perfectly but when you interchange the 2 lines marked as replace, there will be a deadlock. Is there a better way to deal with such a situation when you have different number of sends and receives?

package main

import "fmt"
import "strconv"

func main() {
    a := make(chan string)
    b := make(chan string)

    go func() {
        for i := 0; i < 2; i++ {
            go func(i int) {
                fmt.Println(<-a)
                b <- strconv.Itoa(i) + "b" // replace
                a <- strconv.Itoa(i) + "a" // replace
            }(i)
        }
    }()

    a <- "0"
    for i := 0; i < 2; i++ {
        fmt.Println(<-b)
    }
}

EDIT: using a select statement, there's a chance that a gets picked up by the select and there's still no way to prevent a deadlock because the goroutines can't execute

package main

import "fmt"
import "strconv"

func main() {
    a := make(chan string)
    b := make(chan string)
    c := make(chan bool)
    cancel := make(chan bool)

    go func() {
        for i := 0; i < 2; i++ {
            go func(i int) {
                fmt.Println(<-a)
                b <- strconv.Itoa(i) + "b" // replace
                a <- strconv.Itoa(i) + "a" // replace
                c <- true
            }(i)
        }
    }()

    go func() {
        <-c
        <-c
        cancel <- true
    }()

    a <- "0"

loop:
    for {
        select {
        case ain := <-a:
            fmt.Println("select", ain)
        case bin := <-b:
            fmt.Println("select", bin)
        case <-cancel:
            break loop
        }
    }
}
  • 写回答

1条回答 默认 最新

  • dongmian8108 2017-06-01 12:34
    关注

    Use select:

    package main
    
    import "fmt"
    import "strconv"
    
    func main() {
        a := make(chan string)
        b := make(chan string)
    
        go func() {
            for i := 0; i < 2; i++ {
                go func(i int) {
                    fmt.Println(<-a)
                    b <- strconv.Itoa(i) + "b" // replace
                    a <- strconv.Itoa(i) + "a" // replace
                }(i)
            }
        }()
    
        // regardless of which comes in first, this will handle it 
        select {
        case ain <- a:
            fmt.Println("sent a", ain)
        case bin <- b:
            fmt.Println("sent b", bin)
        case <- cancel:
            break
        }
    }
    

    That example will sit and block for an item sent on either a or b channels.

    Optionally I usually set a cancel token or a timeout.

    Your original code deadlocks on the switch because you sent on B, where you were only listening on A. Golang requires you to be listening on the channel BEFORE you ever send to it. This is the pattern for multiple channels, not knowing which you are going to get first.

    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度