硬件

内存

作为并发编程一个基础硬件知识储备,首先要说的就是内存了,总的来说在绝大多数情况下把内存的并发增删改查模型搞清楚了其他的基本上也是异曲同工之妙。

内存芯片——即我们所知道的内存颗粒,是一堆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
}

而关于多协程顺序性方面的实现方式,也可以比着葫芦画瓢写出来,这里就不再赘述了。

搬砖例子

假设在左边有三堆散乱的砖,我们需要将其从左边搬运到右边并堆放整齐,这样的一个工作我们从并发模型来看有哪些比较可执行的实现方式呢:

  1. 每堆砖头分配固定的人数,堆砖时为保证堆叠整齐度,采用排队的方式一个一个按先后顺序堆叠
  2. 拿一个人专职在左边递砖,若干人从左边的递砖人处拿砖,搬砖后在右边排队堆叠
  3. 左边专人递砖,右边专人堆砖,若干搬砖人只负责搬砖

这也是并发编程模型中比较常用的编程思路,在以后遇到类似问题的时候可以想想这个例子。

一个实际案例

我们以一个实际的案例作为结束,这个案例是导出某云平台所属设备信息的代码,里面包含有多协程拉取数据的实例,整体的流程如下:

  1. 参数初始化
  2. 定义一个接收协程结束的信息通道
  3. 开启N个协程
  4. 协程调用API获取信息,按分页参数每个协程获取(总数/N)信息,每次page=X+N
  5. 每次获取的信息放入excel缓冲区
  6. 当最后的分页获取不到信息时向通道写入东西表示该协程任务完成
  7. 主进程循环获取每个协程结束的信息,直到所有协程任务完成
  8. 将excel缓冲区数据写入excel文件
  9. 结束

连接如下:

https://github.com/cm-heclouds/onenet_device_export/releases/tag/2018-latest

当然,这个案例在并发上其实还存在较大的提升空间,聪明的大家看看结合搬砖的例子来怎么提升呢。

Golang并发编程基础的更多相关文章

  1. golang并发编程

    golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...

  2. python中并发编程基础1

    并发编程基础概念 1.进程. 什么是进程? 正在运行的程序就是进程.程序只是代码. 什么是多道? 多道技术: 1.空间上的复用(内存).将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就 ...

  3. Java并发编程基础

    Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...

  4. TCP与UDP比较 以及并发编程基础知识

    一.tcp比udp真正可靠地原因 1.为什么tcp比udp传输可靠地原因: 我们知道在传输数据的时候,数据是先存在操作系统的缓存中,然后发送给客户端,在客户端也是要经过客户端的操作系统的,因为这个过程 ...

  5. Golang - 并发编程

    目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...

  6. 并发-Java并发编程基础

    Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...

  7. Java并发编程系列-(1) 并发编程基础

    1.并发编程基础 1.1 基本概念 CPU核心与线程数关系 Java中通过多线程的手段来实现并发,对于单处理器机器上来讲,宏观上的多线程并行执行是通过CPU的调度来实现的,微观上CPU在某个时刻只会运 ...

  8. Java并发编程基础三板斧之Semaphore

    引言 最近可以进行个税申报了,还没有申报的同学可以赶紧去试试哦.不过我反正是从上午到下午一直都没有成功的进行申报,一进行申报 就返回"当前访问人数过多,请稍后再试".为什么有些人就 ...

  9. Java高并发编程基础三大利器之CountDownLatch

    引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...

随机推荐

  1. Python 为什么用 # 号作注释符?

    关于编程语言中的注释,其重要性基本上已为大家所共识. 然而关于注释的规范,这个话题就像我们之前聊过的缩进.终止符和命名方式一样,众口难调. 注释符通常可分为两种,即行注释与块注释(inline/blo ...

  2. 小程序开发全栈1.2/3/4组件、flex布局、样式

    1.2 组件 1.2.1 text组件 编写文本信息,类似于HTTP中的span 1.2.2 view组件 容器,类似于HTTP中的div 1.2.3 image组件 图片显示组件 1.3 页面fle ...

  3. Google公布编程语言排名,第一竟然是他?

      没想到吧,Python 又拿第一了! 在 Google 公布的编程语言流行指数中,Python 依旧是全球范围内最受欢迎的技术语言!   01 为什么 Python 会这么火? 核心还是因为企业需 ...

  4. Ribbon负载均衡接口

    IRule--负载均衡规则 1.RounRobinRule:轮询负载均衡,通过累加取余获取服务,默认规则 2.RandomRule:随机负载均衡 3.WeightedResponseTimeRule: ...

  5. Docker 入门教程(3)——Dockerfile

    Dockerfile Dockerfile是一个文本文件,用来定制镜像. 镜像是分层存储的,前一层会是下一层的基础.而镜像的定制就是定制每一层镜像在上一层做了什么改变. Dockerfile其内包含一 ...

  6. Flutter 实现酷炫的3D效果

    老孟导读:此文讲解3个酷炫的3D动画效果. 下面是要实现的效果: Flutter 中3D效果是通过 Transform 组件实现的,没有变换效果的实现: class TransformDemo ext ...

  7. Markdown画图(mermaid)学习

    简介 目前博客园支持mermaid的graph,subgraph,sequenceDiagram,gantt,classDiagram mermaid(美人鱼), 是一个类似markdown,用文本语 ...

  8. 水题----根据O出现次数判断分数

    There is an objective test result such as \OOXXOXXOOO". An `O' means a correct answer of a prob ...

  9. 风速风向 UV 相互转换

    这里以c#为例将风的uv分量转成风向风速(别的语言类似) 风向是以y轴正方向为零度顺时针转 UV转风速风向 1 double v ;//v分量 2 double u;//u分量 3 double fx ...

  10. ROS 机器人技术 - 广播与接收 TF 坐标

    上次我们学习了 TF 的基本概念和如何发布静态的 TF 坐标: ROS 机器人技术 - TF 坐标系统基本概念 ROS 机器人技术 - 静态 TF 坐标帧 这次来总结下如何发布一个自定义的 TF 坐标 ...