defer 与闭包,go 并发常见问题

defer 与闭包

  • 闭包复制的是原对象指针,这就很容易解释闭包的延迟引用现象。
  • defer
    • defer函数的参数,是在defer函数被定义的时候就已经明确了。
    • defer函数的执行顺序是后进先出。
    • defer函数可以操作返回值

根据以上两条规则我们来看如下测试代码,

func main() {
   
   a := 100000
   println(a)
   //1. 单独defer输出--猜想下它的输出
   defer println("defer :", &a, a)
   //2. defer 配合闭包--猜想下它的输出
   defer func() {
    println("defer fun :", &a, a) }()
   //3. defer 配合闭包与入参
   defer func(a int) {
    println("defer fun with param :", &a, a) }(a)
   a++
   println(a)
}
  1. 先看a的指针地址
    12都是a原先地址,但是3使用了入参,go的入参是值传递,所哟3的指针地址跟12不同
  2. 在看a的值
    2闭包复制的是对象指针,取数的时候是最新的数值10001
    1和3取的值是在defer函数被定义的时候就已经明确了。为10000

所以输出如下:

100000
100001
defer fun with param : 0xc0000446e8 100000
defer fun : 0xc000044710 100001
defer : 0xc000044710 100000
进程 已完成,退出代码为 0

Go 并发注意事项

  1. goroutine泄露
  • 泄露的原因:
    如果routine在运行中被阻塞,或者速度很慢,不会正常关闭routine时就会泄漏。阻塞分为两种情况:

    • 写channel时,channel被写满了。
      写一个close的channel会panic;
      [图片]

    • 读channel时,channel被读空了。
      读一个close的channel不会panic,会返回相应的零值。
      [图片]

  • 防止泄露:

    • 尽量选择一个合适的缓冲区大小,可以减少协程阻塞
    • 用select监听多个 case。

举个例子

//选择一个合适的缓冲区大小
myChan = make(chan int, 10) 

// 非阻塞读一次
select {
   
    case msg := <- myChan:
        fmt.Println(msg)
    default:
        fmt.Println("No Msg")
}

// 阻塞<=1s读
for {
   
    select {
   
        case msg := <- myChan:
            fmt.Println(msg)            
            return msg
        case <-time.After(1 * time.Second):
            fmt.Println("You're too slow.")
            return ""
        default:
            fmt.Println("No Msg")        
            time.Sleep(50 * time.Millisecond)
    }
}

// 非阻塞写
select {
   
    case myChan <- "message":
        fmt.Println("sent the message")
    default:
        fmt.Println("no message sent")
}

遵循一个约定:谁创建,谁停止(谁创建goroutine,谁负责停止goroutine)

  1. 同步
    在生产者消费者模型中,主线程需要等待所有消费者退出后再结束。这里需要一个信号量,在go语言中我们可以使用WaitGroup 进行信息同步,当然也可以使用一个单独的channel 传递结束信息。
  • 使用WaitGroup
func producer(ch chan int) {
   
   defer close(ch) // defer保证异常退出时自动关闭channel
   for i := 0; i < 6; i+
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值