一。并发&并行多线程
一个应用程序 ---> 一个进程 ---> 运行在本身内存地址空间里的独立执行体 ---> 同一个内存地址空间的一块儿工做的多个线程并发
一个并发程序 ---> 多个线程来执行任务 ---> 某个时间点同时运行在多核或者多处理器 ---> 并发&并行函数
---> 某个时间点同时运行在单个处理器 --\---> 并发&不并行性能
并行是一种经过使用多处理器以提升速度的能力。因此并发程序能够是并行的,也能够不是。测试
公认的,使用多线程的应用难以作到准确,最主要的问题是内存中的数据共享,它们会被多线程以没法预知的方式进行操做,致使一些没法重现或者随机的结果(称做 竞态
)操作系统
并发方式:线程
1.肯定性的(明肯定义排序)code
2.非肯定性的(加锁/互斥从而未定义排序)---> 竞态协程
不要使用全局变量或者共享内存,它们会给你的代码在并发运算的时候带来危险。排序
解决之道:
1.同步不一样的线程,对数据加锁,这样同时就只有一个线程能够变动数据
2.有个被称做 Communicating Sequential Processes(顺序通讯处理)
(CSP, C. Hoare 发明的)
3.还有一个叫作 message passing-model(消息传递)
(已经运用在了其余语言中,好比 Erlang)
二。go的协程
在 Go 中,应用程序并发处理的部分被称做 goroutines(协程)
协程 ---> 工做在相同的地址空间 ---> 共享内存的方式必定是同步的;这个可使用 sync
包来实现(不推荐)
---> 使用 channels
来同步协程
特色:
1.使用少许的内存和资源:使用 4K 的栈内存就能够在堆中建立它们
2.对栈进行了分割,从而动态的增长(或缩减)内存的使用;栈的管理是自动的,但不是由垃圾回收器管理的,而是在协程退出后自动释放
3.协程能够运行在多个操做系统线程之间,也能够运行在线程以内
4.使用少许的操做系统线程就能拥有任意多个提供服务的协程,并且 Go 运行时能够聪明的意识到哪些协程被阻塞了,暂时搁置它们并处理其余协程
5.存在两种并发方式:肯定性的(明肯定义排序)和非肯定性的(加锁/互斥从而未定义排序)。Go 的协程和通道理所固然的支持肯定性的并发方式(例如通道具备一个 sender 和一个 receiver)
实现形式:
关键字 go
调用 ---> 一个函数或者方法 ---> 在当前的计算过程当中开始一个同时进行的函数 ---> 在相同的地址空间中而且分配了独立的栈(栈分割)
协程的栈会根据须要进行伸缩,不出现栈溢出;开发者不须要关心栈的大小。当协程结束的时候,它会静默退出:用来启动这个协程的函数不会获得任何的返回值
三。go协程并行:
Go 默认没有并行指令,只有一个独立的核心或处理器被专门用于 Go 程序,不论它启动了多少个协程;因此这些协程是并发运行的,但他们不是并行运行的:同一时间只有一个协程会处在运行状态
在 gc 编译器下(6g 或者 8g)你必须设置 GOMAXPROCS 为一个大于默认值 1 的数值来容许运行时支持使用多于 1 个的操做系统线程,全部的协程都会共享同一个线程除非将 GOMAXPROCS 设置为一个大于 1 的数。当 GOMAXPROCS 大于 1 时,会有一个线程池管理许多的线程。经过 gccgo
编译器 GOMAXPROCS 有效的与运行中的协程数量相等。假设 n 是机器上处理器或者核心的数量。若是你设置环境变量 GOMAXPROCS>=n,或者执行 runtime.GOMAXPROCS(n)
,接下来协程会被分割(分散)到 n 个处理器上。更多的处理器并不意味着性能的线性提高。有这样一个经验法则,对于 n 个核心的状况设置 GOMAXPROCS 为 n-1 以得到最佳性能,也一样须要遵照这条规则:协程的数量 > 1 + GOMAXPROCS > 1。
因此若是在某一时间只有一个协程在执行,不要设置 GOMAXPROCS!
还有一些经过实验观察到的现象:在一台 1 颗 CPU 的笔记本电脑上,增长 GOMAXPROCS 到 9 会带来性能提高。在一台 32 核的机器上,设置 GOMAXPROCS=8 会达到最好的性能,在测试环境中,更高的数值没法提高性能。若是设置一个很大的 GOMAXPROCS 只会带来轻微的性能降低;设置 GOMAXPROCS=100,使用 top
命令和 H
选项查看到只有 7 个活动的线程。
增长 GOMAXPROCS 的数值对程序进行并发计算是有好处的;
总结:GOMAXPROCS 等同于(并发的)线程数量,在一台核心数多于1个的机器上,会尽量有等同于核心数的线程在并行运行。