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 ...
随机推荐
- 推荐收藏:100道Linux笔试题,能拿90分以上的都去了BAT
本套笔试题共100题,每题1分,共100分.(参考答案在文章末尾) 1. cron 后台常驻程序 (daemon) 用于: A. 负责文件在网络中的共享 B. 管理打印子系统 C. 跟踪管理系统信息和 ...
- Shell基本语法---case语句
case语句 格式 case 变量 in 值1 ) 执行动作1 ;; 值2 ) 执行动作2 ;; 值3 ) 执行动作3 ;; .... * ) 如果变量的值都不是以上的值,则执行此程序 ;; esac ...
- 一步步教你用Prometheus搭建实时监控系统系列(一)——上帝之火,普罗米修斯的崛起
上帝之火 本系列讲述的是开源实时监控告警解决方案Prometheus,这个单词很牛逼.每次我都能联想到带来上帝之火的希腊之神,普罗米修斯.而这个开源的logo也是火,个人挺喜欢这个logo的设计. 本 ...
- Mybatis(六)逆向工程generator
逆向工程概述: MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代 ...
- 面试题二十二:链表中倒数第k个节点
方法一:双指针法定义两个指针A.B,A先走k-1步后再一起走,直到A.next==null注意: 1.链表为空 2.链表长度小于k 3.k<=0 当题目是求链表的中间节点时,可以两个指针从开头开 ...
- Vue、Nuxt服务端渲染,NodeJS全栈项目,面试小白的博客系统~~
Holle,大家好,我是李白!! 一时兴起的开源项目,到这儿就告一段落了. 这是一个入门全栈之路的小项目,从设计.前端.后端.服务端,一路狂飙的学习,发量正在欣喜若狂~~ 接触过WordPress,H ...
- 使用AB对Nginx压测和并发预估
简介 ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基于URL的. # 1.ab每次只能测试一个URL,适合做重复压力测试 # 2.参数很多,可以支持添加c ...
- Linux阶段总结
Linux总结 一.学习心得: 在学习本阶段关于Linux阶段的课程时,让我对Linux有了一个大概的了解. 我了解到Linux操作系统是基于最初的Unix系统而开发出来的: 在学习Linux的时候, ...
- jmeter控制器入门笔记一
@@@@@@@@@@@@@@@ 千里之行 今天记录一下个人才使用控制器时的一些心得.逻辑控制器在jmeter中有很多种,个人根据官方解释理解的作用就是:通过控制器可以更好地控制请求的执行顺序.jmet ...
- LQB2017A02跳蚱蜢
为什么第二题就这么难呜呜呜,这不是为难我吗!!! 可以明确的是,又是一个bfs 最少路径,找满足条件的那个层数 #include<iostream> #include<stdio.h ...