Golang常见问题

	// 三种阻塞方法
	defer func() {
		for {
		}
	}()
	defer func() {
		select {}
	}()
	defer func() {
		<-make(chan bool)
	}()
	// 常见坑
	/*
		1.不定参数是空接口类型时,传接口数组和变参是都可以通过,但是得到的参数不同
		2.数组是值传递
		3.map遍历是无序的。
		4.命名的返回值内,同名的局部变量被屏蔽。
		5.recover必须在defer函数中运行,直接调用是无效的
		6.mian提前退出,goroutine无法保证完成任务
		7.睡眠不能保证goroutine运行完成
		8.独占cpu导致其他goroutine饿死, runtime.GOMAXPOROCS(1)  runtime.Gosched()
		9.goroutine和main是并发不是顺序。
		10.defer的for循环闭包引用会导致拿到的都是最后一个变量值
		11.for循环内部defer会导致资源延迟释放,可以在for循环内添加一个局部函数来解决延迟问题。
		12.切片引用会导致整个数组被锁定。当切片引用大数组的小部分内容时,会导致大数组久久不能释放。解决办法就是克隆数据。
		13.空指针和空接口不等价。特别是返回error时,自定义的错误类型更要注意区别。
		14.内存地址会发生变化,指针会做同步,但非指针类型的uintptr不会对此变化做同步。同理cgo不能保存go的对象地址。
		15.死循环的goroutine无法释放引用的资源,使用context可以使不用的goroutine释放。避免goroutine泄露。
	*/

	// 面向并发的内存模型
	/*
		1.一般系统级别的线程固定大小栈:2M;goroutine以2/4K启动,动态伸缩可达1G。
		2.go有自己的调度器,以n个线程调度m个goroutine。
		3.goroutine是半抢占式的协作调度。发生在用户态。
		4.只有当前goroutine发生阻塞是才会导致调度。
		5.runtime.GOMAXPROCS(X)控制当前正常非阻塞goroutine的系统线程数目。
		6.原子操作:
			并发编程中 最小的切不可并行化 的操作
			sync.Mutex通过互斥可以保证原子性:麻烦且效率低
			sync/atomic
			sync.Once:单件模式
		7.顺序一致性内存模型:
			同步原语确定两个事件的顺序。
			channel
			sync.Mutex
			可通过cannel的缓存大小控制goroutine的并发大小。

	*/
	// 常见的并发模式
	/*
		CSP:通讯顺序进程-同步通信
		并行一般是简单的大量重复,如GPU对图像的大量并行计算。
		并发:并发完全可以顺序执行,只有真正的多核CPU上才有可能着呢张的同时运行。
		并发编程中对共享资源的控制:go提倡不要通过共享内存通信,而是通过通信来共享内存。
		虽然引用计数这种并发可以通过原子操作很好的实现,但是通过channel来控制访问可以写成更加简洁正确的程序。

		生产者消费者模型:直接使用channel一句话完成:生产者只写,消费者range

		发布订阅模型

		控制并发数:带缓存的channel,而且可以通过获取channel的空闲数来反映并发使用率。

		goroutine安全退出:
		chan bool来控制goroutine退出,sync.WaitGroup来让main等待goroutine的退出时的清理动作。
		context包用于处理单个请求的多个goroutine之间的请求域的数据、超时、退出等操作。context可以代替cannel和waitgroup组合。



	*/
	// 错误和异常
	/*
		为了增加程序的健壮性,防止外部引用的包异常导致我们的程序异常。使用recover统一获取panic
		errors.Wrap和errors.WrapWithCode是对error的二次包装
		errors.ToJson/FromJson可以通过json网络传播error

		error是接口,给该接口返回空指针,外部接收到的接口不是nil,而是个空 指针的接口。
		错误:func returnerr()error{
			var p *MyError=nil
			if bad(){
				p=ErrBad
			}
			return p //此时就算p是nil,外部拿到的返回值也不是nil,而是一个有值的接口,接口值是空指针
		}
		改正:func returnerr()error{
			if bad(){
				return (*MyError)(err)
			}
			return nil
		}


		recover必须在panic中才能捕获异常。
		recover被二次包装在panic中调用也是无效的。defer func(){func(){recover()}()}()
		两个defer嵌套,内部的defer中调用recover也是无效的。 defer func(){defer func(recover()){}()}()
		defer直接调用recover也是无效的。 defer recover()
		panic(nil)会导致无法捕获异常
		有效的调用:
			defer func(recover()){}()
			panic(1)
	*/
发布了264 篇原创文章 · 获赞 23 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/Edu_enth/article/details/103858380