Golang并发模式基础

for-select循环

最基本的模式:

for {
    select {
    case condition 1:
        // ...
    case condition 2:
        // ...
    case condition n:
        // ...
    default:
        // ...
    }
}

每个condition都有机会被执行一次,内部使用了伪随机的策略。如果case条件全部阻塞,那么执行default的条件。

防止goroutine泄露

golang的goroutine无法被GC,只能等待goroutine自动执行结束。因此,如果某些情况下,如果goroutine阻塞了,则只能等待整个程序结束才能回收。虽然goroutine内存消耗少,但是也不能一直申请。

基本的解决思路是传入一个终止chan,代码如下:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    newRandStream := func(done <-chan interface{}) <-chan int {
        randStream := make(chan int)
        go func() {
            defer fmt.Println("newRandStream closure exited")
            defer close(randStream)
            for {
                select {
                case randStream <- rand.Int():
                case <-done:  // 收到终止标记,理解结束
                    return
                }
            }
        }()
        return randStream
    }

    done := make(chan interface{})
    randStream := newRandStream(done)
    for i := 0; i < 3; i++ {
        fmt.Printf("%d, %d\n", i, <-randStream)
    }
    close(done)
    time.Sleep(1 * time.Second)  // 模拟其它工作
}

基本原则是:如果一个goroutine负责创建goroutine,那么它也可以保证停止创建的goroutine。

or-channel

暂时不太理解,留作以后处理

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    var or func(channels ...<-chan interface{}) <-chan interface{}
    or = func(channels <-chan interface{}) <-chan interface{} {
        switch len(channels) {
        case 0:
            return nil
        case 1:
            return channels[0]
        }

        orDone := make(chan interface{})
        go func() {
            defer close(orDone)
            switch len(channels) {
                case 2:
                    select {
                    case <-channels[0]:
                    case <-channels[1]:
                    }
                default:
                    select {
                    case <-channels[0]:
                    case <-channels[1]:
                    case <-channels[2]:
                    case <-or(append(channels[3:], orDone)...):
                    }
            }
        }()
        return orDone
    }

    sig := func(afert time.Duration) <-chan interface{} {
        c := make(chan interface{})
        go func() {
            defer close(c)
            time.Sleep(after)
        }()
        return c
    }
    
    start := time.Now()
    <-or(
        sig(2*time.Hour),
        sig(5*time.Minute),
        sig(1*time.Second),
        sig(1*time.Hour),
        sig(1*time.Minute)
    )
    fmt.Println("done after %v", time.Since(start))
}

错误处理

一般来说,并发进程应该把它们的错误发送到程序的另一个部分,错误中应该有程序的完整状态信息,以便可以做出更明确的决定。构建goroutine时,应该将错误视为一等公民,如果goroutine可能出现错误,那么错误应该和返回值是一起的,通过相同的通信线传递,就像常规的同步函数一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值