目录

前言

自学golang,知识点理解,整理,代码亲自实践分享。(如果哪里不懂,或者写的有问题,欢迎指出,一起进步) 

并发和并行

并发(concurrency)与并行(parallelism)不同。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了(Golang 的并发通过切换多个线程达到减少物理处理器空闲等待的目的)。在很多情况下,并发的效果比并行好,因为操作系统和硬件的总资源一般很少,但能支持系统同时做很多事情。这种 "使用较少的资源做更多的事情" 的哲学,也是指导 Golang 设计的哲学。

如果希望让 goroutine 并行,必须使用多于一个逻辑处理器。当有多个逻辑处理器时,调度器会将 goroutine 平等分配到每个逻辑处理器上。这会让 goroutine 在不同的线程上运行。不过要想真的实现并行的效果,用户需要让自己的程序运行在有多个物理处理器的机器上。否则,哪怕 Golang 运行时使用多个线程,goroutine 依然会在同一个物理处理器上并发运行,达不到并行的效果。

深度理解GMP模型链接参考:

协程 

协程关键字 go 

//执行该结果就会导致,有可能不能输出hello:当主进程已经执行完,协程未执行完,该程序已经结束;如果给主进行设置sleep可等待协程。
func Handle() {
	go func() {
		fmt.Print("hello")
	}()
	fmt.Print("world")
}

使用sync.WaitGroup进行协程阻塞 

//可使用sync.WaitGroup进行协程阻塞
func Handle1() {
	var wg sync.WaitGroup
	wg.Add(2)
	//此时两个协程的执行顺序是乱序的;
	go func() {
		defer wg.Done()
		fmt.Print("hello11")
	}()
	go func() {
		defer wg.Done()
		fmt.Print("hello22")
	}()
	wg.Wait()
	fmt.Print("world")
}

有了协程,那协程之间如何通讯呢? (内存共享/数据共享)

//此时有了协程,那协程之间如何通讯呢?于是就有了channel
func Handle2() {
	ch := make(chan int) //声明通道
	ch <- 10             //通道的接受
	var num = <-ch       //通道的发送
	close(ch)            //通道的关闭
	fmt.Print(num)
}

全局变量进行通讯 (遇到的问题,如何解决)

//当然也可以使用全局变量进行通讯,会遇到什么问题呢?见代码
func Handle3() {
	var wg sync.WaitGroup //声明结构体,就相当于声明php中的类
	//var lock sync.Mutex
	var a int
	wg.Add(2)
	go func() { //单个结果:5000
		defer wg.Done()
		for i := 0; i < 5000; i++ {
			//lock.Lock()//加锁(调用结构体中的公有方法【首字母大写】,就类似于php调用类中的公有方法)
			a += 1
			//lock.Unlock()//解锁
		}
	}()
	go func() { //单个结果:5000
		defer wg.Done()
		for i := 0; i < 5000; i++ {
			//lock.Lock()
			a += 1
			//lock.Unlock()
		}
	}()
	//a的结果为什么不是10000呢?
	//原因:2个协程之间是并发关系,对同一块地址操作时,会发生争抢的情况。
	//解决办法:我们可以使用加锁的方式进行解决争抢的情况。(把加锁注释的代码放开)
	wg.Wait()
	fmt.Print(a)
}

channel通道实例 

//golang中通道(管道)channel就是用来协程间通讯的
//channel通道有:无缓冲的通道,有缓冲的通道,单项通道
//无缓冲的通道:当通道中无数据时,是不能进行发送的;有数据时,是不能进行接受的。(都会进行阻塞)
//实例:
func Handle4() {
	ch := make(chan int)
	//ch := make(chan int,5)
	for i := 0; i < 5; i++ {
		go func() {
			ch <- 10
			fmt.Println("channel接受值;")
		}()
	}
	time.Sleep(time.Second * 3)
	a := <-ch
	fmt.Println("channel发送值:", a)
	//执行该结果本以为主程序有了sleep,结果应该是5次的"channel接受值"和一个"channel发送值:10",循环导致
	//然而,因为无缓冲的通道会进行阻塞,有值时,阻塞写不进去,无值时,阻塞取值取不出。
	//可以尝试将 ch := make(chan int) 修改为 ch := make(chan int,5)
}