2018-03-22

golang 有缓冲channel full不阻塞线程

解决方案一:每次向channel进行写操作前,判断channel长度

note:获取channel长度并不是线程安全的,所以要加锁进行操作。加锁会影响性能,尤其在高并发情况下,会导致大量的线程挂起。此方案不推荐。

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

var tlock sync.Mutex

var testChan = make(chan int, 10)

func f(name string) {
    defer func() {
        wg.Done()
        fmt.Printf("%s :done\n", name)
    }()
    for i := 0; i < 5; i++ {
        time.Sleep(10 * time.Microsecond)
        tlock.Lock()
        tlen := len(testChan)
        if tlen == 10 {
            fmt.Printf("%s :channel is full\n", name)
            tlock.Unlock()
            break
         }
        testChan <- i
        fmt.Printf("%s :%d\n", name, i)
        tlock.Unlock()
    }
}

func main() {
    t := []string{"A", "B", "C", "D"}
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go f(t[i])
    }
    wg.Wait()
}
解决方案二:使用select语句

当case被阻塞的时候,select会执行default语句。

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

var testChan = make(chan int, 10)

func f(name string) {
    defer func() {
        wg.Done()
        fmt.Printf("%s :done\n", name)
    }()
    for i := 0; i < 5; i++ {
        time.Sleep(10 * time.Microsecond)
        select {
        case testChan <- i:
            fmt.Printf("%s :%d\n", name, i)
        default:
            fmt.Printf("%s :channel is full\n", name)
            return
        }
    }
}

func main() {
    t := []string{"A", "B", "C", "D"}
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go f(t[i])
    }
    wg.Wait()
}