Golang频道处理发送!=接收

时间:2017-06-01 11:59:44

标签: go

考虑下面的玩具示例。代码完美无缺,但当你交换标记为replace的2行时,会出现死锁。当你有不同数量的发送和接收时,是否有更好的方法来处理这种情况?

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)
    }
}

编辑:使用select语句,select a有可能被选中,而且仍无法防止死锁,因为goroutines无法执行

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 个答案:

答案 0 :(得分:2)

使用选择:

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
    }
}

该示例将对a或b频道上发送的项目进行阻止和阻止。

我可以选择设置取消令牌或超时。

您的原始代码在交换机上发生死锁,因为您发送了B,您只是在那里收听A. Golang要求您在发送之前先在频道上收听。这是多个渠道的模式,不知道您将首先获得哪个渠道。