Go语言学习笔记-第8章 并发
在最开始,首先讲一下 线程,协程,进程的区别和联系。
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html
单个CPU一次只能运行一个任务
进程:process,是程序的一次执行,每个进程都有独立的内存空间
线程:thread,是轻量级别线程,一个进程可以由多个线程组成,线程是CPU调度的基本单位。线程之间可以共享内存空间。线程之间因为共享内存会实施“锁”机制,有“互斥锁”(Mutual exclusion,Mutex),防止多个线程同时读写某一块内存区域(一次只能一个线程读写一个内存区域)。还有“信号量”(Semaphore),用来保证多个线程不会互相冲突(也就是允许指定个线程访问某一个内存空间)。
协程:也叫微线程,coroutine,是人工可控的,可以在调用中中断然后执行其他的调用。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。内部可以通过yield实现跳转。
子程序:也叫函数
关于内存空间:进程的内存空间是独立的,但是线程之间的空间是可以共享的。进程的内存空间的独立是通过操作系统和硬件MMU协作映射到不同的物理地址上的,所以它们是相互独立的。进程的物理地址一般是不可以跨进程访问的。
一个进程的所有线程是同时执行的。
对于单核CPU,一次只允许一个线程执行。多少核,就是允许多个个线程同时运行
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。
调度器:“scheduler”,它关心的只是怎样把单个cpu的运行拆分成一段一段的“运行片”,轮流分给不同的程序去使用,而在宏观上,因为分配切换的速度极快,就制造出多程序并行在一个cpu上的假象。
8.1 并发的含义
并发:逻辑上具备同时处理多个任务的能力
并行:物理上在同一时刻处理多个任务的能力。并行是并发的理想状态,并行的前提条件是多线程或多进程。
用多线程实现分布式和负载平衡,减轻单进程垃圾回收压力;多线程(LWP)抢夺更多的处理器资源。协程提高处理器时间片效率。
go中可以使用go 创建一个并发任务单元
int的default值为0
这里的go func(x,y int)启动了一个并发执行单元,当a:=100执行结束的时候,执行到go func了,a用的是值传递,相当于go func里的a是个局部变量,这个时候回记录下a和counter()的值,注意这个时候counter()执行完毕c变成1了,然后睡一秒,再执行。在开始睡的时候,main继续向下执行,因为进程退出的时候不会等到并发任务结束,所以需要强制然后睡3秒,在醒来之前可以充分保障go func已经结束了。最后结果是
注意这里居然可以直接写println…,当然直接写fmt.Println也是可以的
8.1.1 Wait
默认只有有限个线程可以同时运行,这些线程的个数和处理器核数相等。可以通过runtime.GOMAXPROCS进行设置,也可以通过环境变量修改。
runtime.NumCPu可以返回机器的核数