Go goroutine协程

本文最后更新于:7 天前

1 关于进程和线程

进程(Process)·就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位,进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个过程都有一个自己的地址空间,一个进程至少有5种基本状态,他们是: 初始态,执行态,等待状态,就绪状态,终止状态

线程: 是进程中的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行 的基本单位

一个进程可以创建多个线程,同一个进程中的多个线程可以并发执行。一个程序要运行的话至少有一个进程

2 关于并发和并行

并发: 多个线程竞争一个位置,竞争到的才可以执行, 每个时间段只有一个线程在执行

并行: 多个线程可以同时执行, 每个时间段可以有多个线程同时执行

通俗的讲: 多线程程序在单核CPU上面运行就是并发,多程序程序在多核CPU上运行就是并行,如果线程数大于cpu核心数,则多线程序在多个cpu上面运行既有并行又有并发

3 Golang中的协程(goroutine)以及主线程

golang中的主线程: (可以理解为线程/也可以理解为进程),在一个Golang程序的主线程上可以起多个协程,Golang中多协程可以实现并行或者并发

协程: 可以理解为用户级别线程,这是对内核透明的,也就是操作系统并不知道有协程的存在,是完全由用户自己的程序进行调度的。Golang的一大特色就是从语言层面原生支持协程,在函数或者方法前面go 关键字就可以创建一个协程, 可以说Golang中的协程就是goroutine

多协程特点: Golang中每个goroutine默认占用内存远比java c的线程少,一个goroutine协程占用的内存非常小,只有2kb左右,多协程goroutine切换调度开销方面远比线程要少,这也是为什么越来越多的大公司使用Golang原因之一

4 通过代码演示

并行执行需求:

​ 在主线程开启一个goroutine 该协程每隔50毫秒输出 “你好Golang”,在主线程中也每隔50毫秒输出”你好golang”,输出10次后,退出程序,要求主线程和goroutine 同时进行

首先我们只是开启一个协程,发现有一个bug 就是main函数不会等待协程执行完成后退出,而是自己执行完成就退出,因为main本身也是一个协程

package main

import (
	"fmt"
	"time"
)

func Sum() {
	for i := 1; i < 10; i++ {
		fmt.Println("sum() 你好golang ", i)
		time.Sleep(time.Millisecond * 10)
	}
}
func main() {
	go Sum()  //开启一个协程	
	for i := 1; i < 10; i++ {
		fmt.Println("main() 你好py", i)
		time.Sleep(time.Millisecond)
	}

}
main() 你好py 1
sum() 你好golang  1
main() 你好py 2
main() 你好py 3
main() 你好py 4
main() 你好py 5
main() 你好py 6
main() 你好py 7
main() 你好py 8
main() 你好py 9
sum() 你好golang  2

使用sync.waitGroup来实现,等待所有协程执行完毕

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup //定义一个sync.waitGroup

func Sum() {
	for i := 1; i < 10; i++ {
		fmt.Println("sum() 你好golang ", i)

	}
	wg.Done() //协程计算减1
}
func sum1() {
	for i := 1; i < 10; i++ {
		fmt.Println("sum1() 你好shell", i)
	}
	wg.Done()  //协程计算减1
}
func main() {
	wg.Add(1)  //协程计算加1
	go Sum()   //开启一个协程
	wg.Add(1)
	go sum1()  //开启一个协程
	wg.Wait()  //等待所有协程执行完成
	fmt.Println("main主线程退出")

}
sum1() 你好shell 1
sum1() 你好shell 2
sum1() 你好shell 3
sum1() 你好shell 4
sum1() 你好shell 5
sum1() 你好shell 6
sum1() 你好shell 7
sum1() 你好shell 8
sum1() 你好shell 9
sum() 你好golang  1
sum() 你好golang  2
sum() 你好golang  3
sum() 你好golang  4
sum() 你好golang  5
sum() 你好golang  6
sum() 你好golang  7
sum() 你好golang  8
sum() 你好golang  9
main主线程退出

5 设置golang 运行时占的cpu

golang程序默认占有所有核心cpu

cpuNum := runtime.NumCPU()//获取当前cpu个数
runtime.GOMAXPROCS(cpuNum - 1 ) //设置程序占有的cpu数量

6 开启多协程执行

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func test(num int) {
	defer wg.Done() //最后执行wg.Done 计算器减1
	for i := 1; i < 4; i++ {
		fmt.Printf("协程(%v),数据%v\n", num, i)
	}

}

func main() {
	for i := 1; i < 5; i++ {
		wg.Add(1)
		go test(i)

	}

	wg.Wait()
	fmt.Println("main退出")
}
/*
协程(4),数据1
协程(4),数据2
协程(4),数据3
协程(1),数据1
协程(1),数据2
协程(1),数据3
协程(3),数据1
协程(3),数据2
协程(3),数据3
协程(2),数据1
协程(2),数据2
协程(2),数据3
main退出
*/

7 统计素数

package main

import (
	"fmt"
	"time"
)

func sumS() {

	for num := 2; num < 120000; num++ {
		flag := true
		for i := 2; i < num; i++ {
			if num%i == 0 {
				flag = false
				break
			}

		}
		if flag {
			//fmt.Println(num)
		}
	}

}

func main() {
	for i := 1; i < 10; i++ {
		fmt.Println(i)
	}
	timeStart := time.Now().Unix()
	sumS()
	timeStop := time.Now().Unix()

	fmt.Println(timeStop - timeStart)
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!