Golang并发编程、串行编程

线程概要

1、什么是进程,线程,多线程?

1
2
3
4
5
开个QQ,开了一个进程;开了迅雷,开了一个进程。
在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。
所以运行某个软件,相当于开了一个进程。在这个软件运行的过程里(在这个进程里),多个工作支撑的完成QQ的运行,那么这“多个工作”分别有一个线程。
所以一个进程管着多个线程。
通俗的讲:“进程是爹妈,管着众多的线程儿子”...

进程: 一个正在运行的程序一般就是一个进程,一个进程中可以有多个线程
线程:一条有序的CPU命令的集合体
多线程:多条有序CPU命令的集合体

备注:一个CPU在同一时刻只能执行一个CPU命令

2、一个CPU可以并发编程(多线程)吗?

例如:3个线程:(上下文切换->线程切换(时间片轮转)) 并发编程
线程1: 5个命令
线程2: 3个命令
线程3: 8个命令

线程1、线程2、线程3在一个CPU的情况下,进行并发编程,由于CPU在同一时间只能执行一个命令,
所以需要通过时间片的轮转

3、并发/并行编程、串行编程
并发编程:多个线程,会有时间片的分配问题,多个线程之间会不断的来回切换
串行编程:按照顺序一一的去执行

4、CPU有分类:
CPU分为两种:物理CPU、逻辑CPU

  • 一个物理CPU可以虚拟出多个逻辑CPU(多核)
  • 8核同一时刻可以最多执行八个cup命令

5、多线程编程优缺点:
优点:分线程可以处理耗时操作,不会出现主线程阻塞
缺点:资源竞争,内存消耗,死锁

golang多线程

1、创建多线程:

  • 多线程通过 go 关键字创建分线程
  • 引入 sync 库控制多线程,var wg sync.WaitGroup 创建实例。
    • wg.Add() 方法声明分线程数。
    • wg.Wait() 方法等待声明的线程全部执行完时(线程数为0时),才会执行后续代码; 在每个分线程。
    • wg.Done() 表示该分线程执行结束,告知主线程(每当分线程执行结束,wg.Add() 声明的线程数减一)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"fmt"
"time"
"sync"
)

var wg sync.WaitGroup

func main() {
wg.Add(2) // 添加两个线程
go f1()
go f2()
wg.Wait() // 等待所有添加的线程执行结束
}

func f1() {
for i:=0; i<100; i++ {
fmt.Println("f1", i)
time.Sleep(1 * time.Seconed) // 等待2s
}
wg.Done() // 当前分线程执行结束,通知主线程
}

func f2(){
for i:=0; i<200; i++ {
fmt.Println("f2", i)
}
wg.Done() // 当前分线程执行结束,通知主线程
}

2、资源竞争、上锁

并发编程由于是CPU在多个线程建来回切换,如果多个线程对同一全局变量进行操作,则无法预测出现的结果(因为CPU在多线程间的切换是随机的)。这时就需要对数据进行上锁,即同一时刻,同一数据只能被一个线程操作。当操作时对该数据上锁,在此期间,其他线程无法操作该数据,只能等待。当该数据的操作完成时,再对其进行解锁,这样等待中的其他线程就可以操作该数据。

检测资源竞争:go run -race main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"fmt"
"math/rand" // 随机数
"time"
"sync"
)

var wg sync.WaitGroup
var counter int
var mutex sync.Mutex // 上锁、解锁

func main() {
wg.Add(2)
incrementor("Foo:")
incrementor("Bar:")
wg.Wait()
}

func incrementor(s string) {
rand.Seed(time.Now().UnixNano())
for i:=0; i<20; i++ {
time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)
mutex.Lock() // 上锁
counter ++
fmt.Println(s, i, "counter:", counter)
mutex.Unlock() // 解锁
}
wg.Done()
}
Author

Ludis

Posted on

2018-01-26

Updated on

2018-02-13

Licensed under

Comments