golang-内联机制&go开发测试

1.go-内联优化机制,如下代码描述

package main
import "fmt"
/*
go 内联优化,根据AST语法树的字符个数,(80) >80 进行优化内联
*/

func add(a, b int) int {
	return a + b
}

//go:noinline ,屏蔽掉系统的内联优化,通过go build -gcflags="-m -m" goInline.go查看
// ./goInline.go:5:6: can inline add with cost 4 as: func(int, int) int { return a + b }
// ./goInline.go:10:6: cannot inline sub: marked go:noinline
// ./goInline.go:13:6: cannot inline main: function too complex: cost 229 exceeds budget 80
// ./goInline.go:16:17: inlining call to add func(int, int) int { return a + b }

func sub(a, b int) int {
	return a - b
}
func main() {
	a := 1
	b := 2
	fmt.Println(add(a, b))
	fmt.Println(sub(a, b))
}

2.for循环中的坑
例如:

package main

import "fmt"

func main() {
	in := []int{1, 2, 3}
	var out []*int
	// for _, v := range in {
	// 	out = append(out, &v)
	// }

	// for _, n := range out {
	// 	fmt.Println(n)
	// }
	// 如下结果都是一样,产生如此的原因,v是单个变量,(内存地址是不变的,每次迭代都采用的新值,并且他们都指向了相同的值)
	// 0xc0000160c0
	// 0xc0000160c0
	// 0xc0000160c0

	// 解决:使用一个中间变量犯法
	for _, v := range in {
		v := v
		out = append(out, &v)
	}
	for _, n := range out {
		fmt.Println(n)
	}
}

// 除此之外,避免在循环内使用Wait,defer等方法。根据实际情况处理。

3.channel阻塞

1 func doReq(timeout time.Duration) obj {
2    // ch :=make(chan obj)
3    ch := make(chan obj, 1)
4    go func() {
5      obj := do()
6      ch <- result
7    } ()
8    select {
9       case result = <- ch:
10        return result
11      case <- time.After(timeout):
12        return nil 
13    }
14 }

如上代码,子 goroutine 执行 do 函数并通过第 6 行的通道 ch 将结果发送回父 goroutine。
子 goroutine 将在第 6 行阻塞,直到父 goroutine 在第 9 行从 ch 接收到结果为止。同时,
父 goroutine 将在 select 阻塞,直到子 goroutine 将结果发送给 ch(第 9 行)或超时
(第 11 行)。如果超时先发生,则父 goroutine 将从 doReq 第 12 行返回,这会导致没有 goroutine 从 ch 读取数据,子 goroutine 就会一直堵塞在第 6 行。解决办法是将 ch 
从无缓冲的通道改为有缓冲的通道,因此子goroutine 即使在父 goroutine 退出后也始终
可以发送结果。

***无缓冲通道
定义一个通道时,容量为0或者不设置容量,即为无缓冲通道,此通道特点,必须发送者&接受者都就绪了才能通信
package main

import (
	"fmt"
	"time"
)

func main() {
	// 创建一个无缓存的channel
	ch := make(chan int, 0)

	// len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小,两者这里永远都是0
	fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))

	// 新建协程
	go func() {
		for i := 0; i < 3; i++ { // 写三次
			fmt.Printf("子协程:i = %d\n", i)
			ch <- i // 往chan写内容
			fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
		}
	}()

	// 延时2秒
	time.Sleep(2 * time.Second)

	for i := 0; i < 3; i++ { // 必须读三次
		num := <-ch // 读管道中内容,没有内容前,阻塞
		fmt.Println("num = ", num)
	}

}
缓冲通道:
package main

import (
    "fmt"
    "time"
)

func main() {
    //创建一个有缓存的channel
    ch := make(chan int, 3) //容量是3

    //len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小
    fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))

    //新建协程
    go func() {
        for i := 0; i < 10; i++ { //这里数据量大于管道容量,会出阻塞
            ch <- i //往chan写内容,如果主协程没读的话,写满3个就会阻塞在此
            fmt.Printf("子协程[%d]: len(ch) = %d, cap(ch)= %d\n", i, len(ch), cap(ch))
        }
    }()

    //延时
    time.Sleep(2 * time.Second)

    for i := 0; i < 10; i++ { //这里数据量大于管道容量,会出阻塞
        num := <-ch //读管道中内容,没有内容前,阻塞
        fmt.Println("num = ", num)
    }

}
总结:
无缓冲: 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-c1 接手了这个参数,
那么c1<-1才会继续下去,要不然就一直阻塞着。
有缓冲: c2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二
个值的时候,第一个还没被人拿走,这时候才会阻塞。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值