golang 学习(二十九)协程(gorouting)介绍以及sync.WaitGroup,素数

协程(gorouting)介绍以及sync.WaitGroup,素数

进程、线程

  1. 进程(Proces)就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基
    本单位,进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进 程都有一个自己的地址空间。一个进程至少有 5种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。通俗的讲进程就是一个正在执行的程序。
  2. 线程 是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行的基 本单位
  3. 一个进程可以创建多个线程,同一个进程中的多个线程可以并发执行,一个程序要运行的话 至少有一个进程

并行和并发

  1. 并发:多个线程同时竞争一个位置,竞争到的才可以执行,每一个时间段只有一个线程在执 行
  2. 并行:多个线程可以同时执行,每一个时间段,可以有多个线程同时执行。
  3. 通俗的讲多线程序在单核 CPU 上面运行就是并发,多线程序在多核 CUP 上运行就是并 行,如果线程数大于 CPU核数,则多线程序在多个 CPU 上面运行既有并行又有并发
    在这里插入图片描述
    在这里插入图片描述

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

  1. golang 中的主线程:(可以理解为线程/也可以理解为进程),在一个 Golang 程序的主线程 上可以起多个协程.Golang中多协程可以实现并行或者并发
  2. 协程:可以理解为用户级线程,这是对内核透明的,也就是系统并不知道有协程的存在,是 完全由用户自己的程序进行调度的
  3. Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go 关键字就可创建一个协程。可以说 Golang中的协程就是goroutine
    在这里插入图片描述
import (
	"fmt"
	"testing"
	"time"
)
func otherFun() {
	fmt.Println("开启一个协程")
	time.Sleep(time.Millisecond * 100) //毫秒	
}
func TestGorouting(t *testing.T) {
	go otherFun() //表示开启一个协程
	for i := 0; i < 10; i++ {
		fmt.Println("main()_", i)
		time.Sleep(time.Millisecond * 100) 
	}
}

在这里插入图片描述

  1. Golang 中的多协程有点类似其他语言中的多线程
  2. 多协程和多线程:Golang 中每个 goroutine (协程) 默认占用内存远比 Java 、C 的线程少,OS线程(操作系统线程)一般都有固定的栈内存(通常为 2MB 左右),一个 goroutine (协程) 占用内存非常小,只有 2KB左右,多协程 gorutine 切换调度开销方面远比线程要少这也是为什么越来越多的大公司使用 Golang 的原因之一

Gorutine 的使用以及 sync.WaitGroup

func otherFun() {
	for i := 0; i < 10; i++ {
		fmt.Printf("other()_%v\n",i)
		time.Sleep(time.Millisecond * 100) //毫秒
	}
}
func TestGorouting(t *testing.T) {
	go otherFun() //表示开启一个协程
	for i := 0; i < 10; i++ {
		fmt.Println("main()_", i)
		time.Sleep(time.Millisecond * 50) //毫秒 
	}
	// 主线程执行完毕后,即使协程没有执行完毕程序也会退出
	//一种方法 time.Sleep(time.Second*1)//等待1s 退出
}

sync.WaitGroup 可以实现主线程等待协程执行完毕

var wg sync.WaitGroup 
func otherFun(n int) {
	defer wg.Done() //协程计数-1
	for i := 0; i < 10; i++ {
		fmt.Printf("other()_第%v个协程值%v\n", n, i)
		time.Sleep(time.Millisecond * 100) //毫秒
	}
}

// 实现并发和并行
func TestGorouting(t *testing.T) {
	for i := 0; i < 10; i++ {
		wg.Add(1)//协程计数+1
		go otherFun(i) //表示开启一个协程
	}
	for i := 0; i < 10; i++ {
		fmt.Println("main()_", i)
		time.Sleep(time.Millisecond * 50)
	}
	wg.Wait()//等待协程执行完成
}

多次执行上面的代码,会发现每次打印的数字的顺序都不一致。这是因为 10 个 goroutine
是并发执行的,而 goroutine 的调度是随机的。

设置 Golang 并行运行的时候占用的 cup 数量

  1. Go 运行时的调度器使用 GOMAXPROCS 参数来确定需要使用多少个 OS 线程来同时执行 Go 代码。默认值是机器上的 CPU核心数。例如在一个 8 核心的机器上,调度器会把 Go 代码同 时调度到 8 个 OS 线程上
  2. Go 语言中可以通过 runtime.GOMAXPROCS()函数设置当前程序并发时占用的 CPU 逻辑核心 数
  3. Go1.5 版本之前,默认使用的是单核心执行。Go1.5 版本之后,默认使用全部的 CPU 逻辑核 心数
//获取当前计算机上面的 Cup 个数
cpuNm := runtime.NumCPU()
fmt.Printl("cpuNm=", cpuNm)
//可以自己设置使用多个 cpu
runtime.GOMAXPROCS(cpuNm - 1)

计算1-240000的素数


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

var wg sync.WaitGroup 
func Num(n int) {
	defer wg.Done()
	var start = (n-1)*15000 + 1
	var end = n * 15000
	for i := start; i < end; i++ {
		if n > 1 {
			var flag = true
			for j := 2; j < i; j++ {
				if i%j == 0 {
					flag = false
					break
				}
			}
			if flag {
				//fmt.Printf("%v is 素数\n",i)
			}
		}
	}

}
func TestNum(t *testing.T) {
	var startTime = time.Now().Unix()
	for i := 1; i <= 8; i++ {
		wg.Add(1)
		go Num(i)
	}
	wg.Wait()
	var endTime = time.Now().Unix() - startTime
	fmt.Println(endTime) //1到2s cpu 4核心 8 线程
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值