Golang并发编程基础
硬件
内存
作为并发编程一个基础硬件知识储备,首先要说的就是内存了,总的来说在绝大多数情况下把内存的并发增删改查模型搞清楚了其他的基本上也是异曲同工之妙。
内存芯片——即我们所知道的内存颗粒,是一堆MOS管的集合,在半导体称呼里面,很多MOS管组成一个半导体(组module),很多个module组成一个管芯(die),这个die即是内存颗粒,当然,更上一级即很多die组成的东西叫做晶圆(wafer)。
简单来说,每8个MOS管组成的电路可以表示一个字节,比如ASCII的‘A’,我们使用65表示,即0100 0001,那么8个MOS分别使用低-高-低-低-低-低-低-高电位即可表示字符A。
在对内存的写入和读取时,通常也是按照8个字开始作为一组进行操作,我们现在常用的CPU是64位,可以一次性处理64/8=8个字节的数据。
总线
首先明确一个概念:总线是线但是也不是线,以下是来自百科的解释:
总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道。
一个CPU要操作内存的数据,是通过总线来进行操作的,通常来说内存的读写操作不是一个CPU指令周期能完成的,如果多个程序在同时操作一个内存地址,则有各种意外的读写操作。
CPU
在单核CPU时期,硬件一次只能处理一个事情,在多任务的情况下不同的任务按需抢占CPU来执行它的代码,这里面就涉及到CPU调度工作,通常情况下,操作系统已经帮我们做了很多事,如果一个编程语言开启的并发操作是交给了操作系统的,那么调度这块不需要太关心,如果像Go这样有自己的协程调度器,还是需要专门了解下特有的调度方式的。
多核时期,基本原理也差不多,在对于硬件的理解上也可以完全参考单核。
CPU通过地址总线去寻找内存地址,比如0x00004567这种,64位CPU最大能操作的地址长度为264,32位操作系统则是232长度,所以为什么32位CPU最大只支持4GB内存呢?
几个代码示例
示例一
package main
import (
"fmt"
)
var A int
func main() {
A = 0
for i:=0;i<100;i++{
A++
}
fmt.Println(A)
}
示例二
package main
import (
"fmt"
"time"
)
var A int
func main() {
A = 0
for j:=0;j<100;j++{
go add()
}
time.Sleep(1*time.Second)
fmt.Println(A)
}
func add(){
A++
return
}
示例一个示例二都将输出什么呢,直接告诉大家结果吧:绝大多数情况下都是100
那么go的协程难道这么听话,我们就完全很happy地编码了吗?先把示例二的100改成10000再试试吧_
我们再看看示例三和示例四:
示例三
package main
import (
"fmt"
)
func main() {
for i:=0;i<10000;i++{
fmt.Println(i)
}
}
示例四
package main
import (
"fmt"
"time"
)
func main() {
for j:=0;j<10000;j++{
go add(j)
}
time.Sleep(1*time.Second)
}
func add(j int){
fmt.Println(j)
return
}
示例三其实没太多好说的,单协程模型,输出也不会有什么意外,而示例四大家猜猜是按照1,2,3...9999这样的顺序呢还是其他输出顺序呢?
综上结果,我们会发现多协程模型里面的东西没有顺序性,对变量的操作也没有原子性。
示例五给出了Golang中最简单的加锁处理方式:
示例五
package main
import (
"fmt"
"time"
"sync"
)
var A int
var LOCK *sync.Mutex
func main() {
A = 0
LOCK = new(sync.Mutex)
for j:=0;j<10000;j++{
go add()
}
time.Sleep(1*time.Second)
fmt.Println(A)
}
func add(){
LOCK.Lock()
A++
LOCK.Unlock()
return
}
而关于多协程顺序性方面的实现方式,也可以比着葫芦画瓢写出来,这里就不再赘述了。
搬砖例子
假设在左边有三堆散乱的砖,我们需要将其从左边搬运到右边并堆放整齐,这样的一个工作我们从并发模型来看有哪些比较可执行的实现方式呢:
- 每堆砖头分配固定的人数,堆砖时为保证堆叠整齐度,采用排队的方式一个一个按先后顺序堆叠
- 拿一个人专职在左边递砖,若干人从左边的递砖人处拿砖,搬砖后在右边排队堆叠
- 左边专人递砖,右边专人堆砖,若干搬砖人只负责搬砖
这也是并发编程模型中比较常用的编程思路,在以后遇到类似问题的时候可以想想这个例子。
一个实际案例
我们以一个实际的案例作为结束,这个案例是导出某云平台所属设备信息的代码,里面包含有多协程拉取数据的实例,整体的流程如下:
- 参数初始化
- 定义一个接收协程结束的信息通道
- 开启N个协程
- 协程调用API获取信息,按分页参数每个协程获取(总数/N)信息,每次page=X+N
- 每次获取的信息放入excel缓冲区
- 当最后的分页获取不到信息时向通道写入东西表示该协程任务完成
- 主进程循环获取每个协程结束的信息,直到所有协程任务完成
- 将excel缓冲区数据写入excel文件
- 结束
连接如下:
https://github.com/cm-heclouds/onenet_device_export/releases/tag/2018-latest
当然,这个案例在并发上其实还存在较大的提升空间,聪明的大家看看结合搬砖的例子来怎么提升呢。
Golang并发编程基础的更多相关文章
- golang并发编程
golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...
- python中并发编程基础1
并发编程基础概念 1.进程. 什么是进程? 正在运行的程序就是进程.程序只是代码. 什么是多道? 多道技术: 1.空间上的复用(内存).将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就 ...
- Java并发编程基础
Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...
- TCP与UDP比较 以及并发编程基础知识
一.tcp比udp真正可靠地原因 1.为什么tcp比udp传输可靠地原因: 我们知道在传输数据的时候,数据是先存在操作系统的缓存中,然后发送给客户端,在客户端也是要经过客户端的操作系统的,因为这个过程 ...
- Golang - 并发编程
目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...
- 并发-Java并发编程基础
Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...
- Java并发编程系列-(1) 并发编程基础
1.并发编程基础 1.1 基本概念 CPU核心与线程数关系 Java中通过多线程的手段来实现并发,对于单处理器机器上来讲,宏观上的多线程并行执行是通过CPU的调度来实现的,微观上CPU在某个时刻只会运 ...
- Java并发编程基础三板斧之Semaphore
引言 最近可以进行个税申报了,还没有申报的同学可以赶紧去试试哦.不过我反正是从上午到下午一直都没有成功的进行申报,一进行申报 就返回"当前访问人数过多,请稍后再试".为什么有些人就 ...
- Java高并发编程基础三大利器之CountDownLatch
引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...
随机推荐
- 耐心看,1个Dubbo漏洞,35道必问面试题,Dubbo没什么可神秘的
Dubbo漏洞 无意中在网上看到了这样的一条新闻,说是我们360监测发现了Dubbo官方发布的危险漏洞通告,而且尴尬的是,世界上受影响最大的居然是中国,有图有真相 我感觉这也从侧面证明了一件事情,就是 ...
- 带你上手阿里开源的 Java 诊断利器:Arthas
本文适合有 Java 基础知识的人群. 本文作者:HelloGitHub-秦人 HelloGitHub 推出的<讲解开源项目>系列,今天给大家带来一款阿里开源的 Java 诊断利器 Art ...
- MongoDB 事务,复制和分片的关系
摘要:本文尝试对Mongo的复制和分布式事务的原理进行描述,在必要的地方,对实现的正确性进行论证,希望能为MongoDB内核爱好者提供一些参考. 1.前言 MongoDB基于wiredTiger提供的 ...
- 疑难杂症1-去掉网站里的特殊编码
编辑器:Visual Studio 2019项目框架:Net Core 3.1 + AutoFac 特殊符号,这是编码UTF-8 + BOM的特殊标记,是隐藏的,但是会被浏览器翻 ...
- web自动化 -- Select(下拉选择框操作)
目标:(现在 select 这种已经很少了.一般都是 ul/li 或者 span/svg) 代码示例:
- CSS3选择器用法小结
1.*通配符选择器 eg:*{margin:0;padding:0;} 2.#id选择符 ID选择器是CSS中效率最高的选择器,使用的时候要保证ID的唯一性 eg:#div{width:960px;m ...
- control+B进入layout文件的xml文本编辑模式
control+B进入layout文件的xml文本编辑模式
- sqlite 显示表内容时乱码,无法正常显示汉字,
把txt文件另存为时,选择编码为utf-8即可
- 图文并茂,带你认识 JVM 运行时数据区
跨平台的本质 关于 JVM, Java 程序员的最熟悉的一句话就是:一处编码,到处执行,指的就是 Java 语言可以通过 JVM 实现跨平台.而跨平台到底跨越了什么这个问题相信很少有人知道,接下来就跟 ...
- Hexo 静态博客指南:建站教程(中)
本文最初发布于我的个人博客Bambrow's Blog,采用 BY-NC-SA 许可协议,转载请注明出处.若有后续更新,将更新于原博客.欢迎去我的博客阅读更多文章! 本文详细记录一下站点建立过程,以便 ...