goroutinue和channel

goroutinue和channel

  • 需求
  • 传统方式实现
  • goroutinue
    • 进程和线程说明
    • 并发和并行
    • go协程和go主线程
    • MPG
    • 设置Go运行的cpu数
  • channel(管道)-看个需求
    • 使用互斥锁、写锁
    • channel 实现
  • 使用select可以解决从管道取数据的阻塞问题(无需手动关闭channel了)
  • goroutinue中使用了recover,解决协程中出现panic,导致程序崩溃问题
  • 素数问题

需求

要求:统计 1-20000的数字中,哪些是素数?
分析思路:
(1)传统的方法中,就是使用一个循环,循环的判断各个数是不是素数
(2)使用并发或并行的方式,将统计素数的任务分配给多个goroutine去完成,这时就会使用到goroutinue

传统方式实现

func main() {now := time.Now()printPrime(1000000)seconds := time.Since(now).Seconds()fmt.Println("time : ", seconds)
}// 打印素数
// 素数定义:仅能被1和它本身整除的大于1的自然数func printPrime(n int) {for i := 2; i <= n; i++ {isPrime(i)}
}// 判断是否是素数func isPrime(n int) bool {if n <= 1 {return false}sqrt := int(math.Sqrt(float64(n))) // 更高效for i := 2; i <= sqrt; i++ {if n%i == 0 {return false}}fmt.Println(n)return true
}

单核 大约需要0.9s左右

goroutinue

进程和线程说明

  1. 进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单元
  2. 线程是进城的一个执行实例,是程序执行的最小单元,他是比进程更小的能独立运行的基本单位
  3. 一个进程可以创建核销多个线程,同一个进程中的多个线程可以并发执行
  4. 一个程序至少有一个进程,一个进程至少有一个线程

并发和并行

  1. 多个线程在单核上执行,就是并发
  2. 多个线程在多核上运行,就是并行

go协程和go主线程

  1. Go主线程:一个狗线程上可以起多个协程,协程是轻量级的线程
  2. Go协程的特点
    • 有独立的栈空间
    • 共享程序堆空间
    • 调度由用户控制
    • 协程是轻量级的线程

MPG

  1. 主线程是一个物理线程,直接作用在cpu上。是重量级的,非常耗费cpu资源
  2. 协程是从主线程开启的,是轻量级别的线程,是逻辑太,对资源消耗相对小
  3. Golang 的协程机制是重要的特点,可以轻松的开启上万个协程。其他编程语言的并发机制一般基于线程的,开启过多的线程,资源耗费大,这里就凸显Golang在并发的优势了

MPG模式基本介绍
M: 操作系统主线程 是物理线程
P: 协程执行需要的上下文
G: 协程
在这里插入图片描述

  1. 当前程序由三个M,如果三个M都在一个cpu运行,就是并发,如果在不同的cpu运行,就是并行
  2. M1、M2、M3 正在执行一个G,M1协程队列有三个,M2协程队列有三个,M3线程队列有两个
  3. go协程是 轻量级的线程,是逻辑态的,Go可以容易的启动上万个协程
  4. 其他程序c/Java的多线程,往往是内核态的,比较重量级,几千个线程可能耗光cpu

在这里插入图片描述1. 分成两个部分来看
2. 原来的情况是M0主线程正在执行Go协程,另外有三个协程在队列等待
3. 如果Go协程阻塞,比如读文件或数据库等
4. 这是就会创建M1主线程(也可能从已有线程中取出M1),并且将等待的3个协程挂到M1下开始执行,M0的主线程下的GO仍然执行文件IO的读写
5.这样MPG调度模拟,可以既让Go执行,同时也不会让队列的其他协程一直阻塞,仍然可以并发或并行执行
6. 等到Go不阻塞了,M0会被放到空闲的主线程继续执行(从已有线程中取),同时GO又会被唤醒

设置Go运行的cpu数

go1.8后,默认让程序运行在多个核上,可以不用设置了

fmt.Println("CPU", runtime.NumCPU())
runtime.GOMAXPROCS(19)

channel(管道)-看个需求

现在要计算1-200的各个数的阶乘,并且把各个数的阶乘写入到map中,最后显示出来。要求使用goroutinue实现
分析:

  1. map不是并发安全,应该会有安全问题
  2. 加锁或者使用channel通信实现
var wg sync.WaitGroup
func main() {wg.Add(200)calcJiCheng(200)
}func calcJiCheng(n int) {m := make(map[int]int64)for i := 1; i <= n; i++ {go jiCheng(i, m)}wg.Wait() // 使用同步等待组,阻塞主线程fmt.Println(m)
}func jiCheng(n int, m map[int]int64) {var sum int64 = 1for i := 1; i <= n; i++ {sum *= int64(i)}m[n] = sumwg.Done()
}

fatal error: concurrent map writes 对map存在并发写操作
java 解决方案,使用 ConcurrentHashMap 或者 手动加锁

使用互斥锁、写锁

var wg sync.WaitGroup// var mutex sync.Mutex // 互斥锁 实现
var mutex sync.RWMutex // 写锁实现func main() {wg.Add(200)calcJiCheng(200)
}func calcJiCheng(n int) {m := make(map[int]int64)for i := 1; i <= n; i++ {go jiCheng(i, m)}wg.Wait() // 使用同步等待组,阻塞主线程fmt.Println(m)
}func jiCheng(n int, m map[int]int64) {defer mutex.Unlock()mutex.Lock()var sum int64 = 1for i := 1; i <= n; i++ {sum *= int64(i)}m[n] = sumwg.Done()
}

这是低水平程序猿首选,哈哈,高级程序猿使用channel解决

channel 实现

  1. channel 本质上是一个数据结构 队列
  2. 数据是先进先出
  3. 线程安全,多goroutinue访问时,不需要加锁,就是说channel本身就是线程安全的
  4. channel时有类型的,一个string的channel只能存放string类型数据

无缓冲管道 var ch = make(chan [2]int64)
有写必有读,缺少一个必死锁,
使用range读必须在写入最后一个关闭通道

缓冲管道 var ch = make(chan [2]int64,3)
写入超过缓冲值,必死锁
没有值读取,必死锁
使用range读必须在写入最后一个关闭通道

管道的读写是一个阻塞操作,我更愿意把其当作消息队列来用

var wg sync.WaitGroup
var ch = make(chan [2]int64)func main() {wg.Add(200)calcJiCheng(200)
}func calcJiCheng(n int) {m := make(map[int]int64)for i := 1; i <= n; i++ {go jiCheng(i, n)}for a := range ch {var num int64 = a[0]var value int64 = a[1]m[int(num)] = value}fmt.Println(m)
}func jiCheng(n int, end int) {var sum int64 = 1for i := 1; i <= n; i++ {sum *= int64(i)}ch <- [2]int64{int64(n), sum}wg.Done()// 关闭channelif n == end {close(ch)}
}

使用select可以解决从管道取数据的阻塞问题(无需手动关闭channel了)

func main() {intChan := make(chan int, 10)for i := 0; i < 10; i++ {intChan <- i}strChan := make(chan string, 5)for i := 0; i < 5; i++ {strChan <- strconv.Itoa(i)}// 传统的方法在遍历管道的时候,如果不关闭会阻塞而导致 deadlock// 问题 在实际开发中,可能我们不好确定什么时候关闭该管道// 可以使用select 方式 解决for {select {case v := <-intChan:fmt.Printf("从intChan读取的数据 %d\n", v)case v := <-strChan:fmt.Printf("从strChan读取的数据 %s\n", v)default:fmt.Printf("取不到了,不玩了  ")return}}
}

goroutinue中使用了recover,解决协程中出现panic,导致程序崩溃问题

如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成程序崩溃,这是我们在goroutinue中使用recover来捕获panic,进行处理,这样即时这个协程发生问题,但主线程不受影响,继续执行

func main() {go hi()go say()time.Sleep(time.Second * 2)
}
func say() {println("say 3333333")}
func hi() {defer func() {if err := recover(); err != nil {fmt.Println("程序出戳了", err)}}()fmt.Println("hi")var a map[string]inta["2"] = 3}

素数问题


var wg sync.WaitGroup
var ch = make(chan int)
var done = make(chan struct{})func main() {now := time.Now()wg.Add(1000)go printPrime(1000)go func() {for i := range ch {fmt.Println("主线程", i)}close(done)}()wg.Wait()close(ch)<-doneseconds := time.Since(now).Seconds()fmt.Println("time : ", seconds)
}// 打印素数
// 素数定义:仅能被1和它本身整除的大于1的自然数func printPrime(n int) {for i := 1; i <= n; i++ {go isPrime(i, n)}
}// 判断是否是素数func isPrime(n int, end int) bool {defer func() {wg.Done()}()if n <= 1 {return false}sqrt := int(math.Sqrt(float64(n))) // 更高效for i := 2; i <= sqrt; i++ {if n%i == 0 {return false}}ch <- nfmt.Println(n)return true
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/829182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

61、回溯-分割回文串

思路&#xff1a; 还是全排列的思路&#xff0c;列出每一种组合&#xff0c;然后验证是否是回文&#xff0c;如果是子串放入path中&#xff0c;在验证其他元素是否也是回文。代码如下&#xff1a; class Solution {// 主方法&#xff0c;用于接收一个字符串s并返回所有可能的…

智能变频三模正弦波控制器

智能变频三模正弦波控制器 前言一、图片介绍总结 前言 不敢动&#xff0c;完全不敢动。多做笔记&#xff0c;完全了解之后再说吧 一、图片介绍 轮毂电机 主角登场 淘宝关于这款控制器的介绍 当然不同的型号功能不同 学习线插上就会转,可以使用继电器控制通断。 电门…

mac资源库的东西可以删除吗?提升Mac运行速度秘籍 Mac实用软件

很多小伙伴在使用mac电脑处理工作的时候&#xff0c;就会很疑惑&#xff0c;电脑的运行速度怎么越来越慢&#xff0c;就想着通过删除mac资源库的东西&#xff0c;那么mac资源库的东西可以删除吗&#xff1f;删除了会不会造成电脑故障呢&#xff1f; 首先&#xff0c;mac资源库…

解决ax = Axes3D(fig2)pycharm画3d图空白不显示问题

明明代码运行正确&#xff0c;却总是显示不出来 绘制出来的也是空白 改一下代码就好了 ax Axes3D(fig2) #原来代码 ax fig2.add_axes(Axes3D(fig2)) #改后代码 修改过后就可以显示了

深入了解MySQL:从基础到特性,全面解读关系数据库管理系统的历史与应用

文章目录 1. MySQL简介1.1 概述1.2 架构与兼容性1.3 开源与社区支持 2. MySQL的历史2.1 创始与初衷2.2 发展历程2.3 在Oracle的持续发展2.4 开源与商业结合 3. MySQL的核心特性4. MySQL在实际应用中的作用4.1 网站建设与内容管理4.2 商业智能与客户关系管理4.3 企业级应用与云集…

线性代数 --- 计算斐波那契数列第n项的快速算法(矩阵的n次幂)

计算斐波那契数列第n项的快速算法(矩阵的n次幂) The n-th term of Fibonacci Numbers&#xff1a; 斐波那契数列的是一个古老而又经典的数学数列&#xff0c;距今已经有800多年了。关于斐波那契数列的计算方法不难&#xff0c;只是当我们希望快速求出其数列中的第100&#xff0…

mysql8.0免安装版windows

1.下载 MySQL下载链接 2.解压与新建my.ini文件 解压的路径最好不要有中文路径在\mysql-8.0.36-winx64文件夹下新建my.ini文件&#xff0c;不建data文件夹(会自动生成) [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录(尽量用双斜杠\\,单斜杠\可能会报错) basedirD:\…

uniapp获取当前位置及检测授权状态

uniapp获取当前位置及检测授权定位权限 文章目录 uniapp获取当前位置及检测授权定位权限效果图创建js文件permission.jslocation.js 使用 效果图 Android设备 点击 “设置”&#xff0c;跳转应用信息&#xff0c;打开“权限即可”&#xff1b; 创建js文件 permission.js 新建…

3d合并的模型为什么没有模型---模大狮模型网

在3D建模中&#xff0c;合并模型是常见的操作&#xff0c;它可以将多个模型合并成一个整体。然而&#xff0c;有时候在合并后却发现部分模型消失了&#xff0c;这可能会让人感到困惑和失望。本文将探讨为什么合并的3D模型中会出现没有模型的情况&#xff0c;并提供一些解决方法…

Web前端一套全部清晰 ③ day2 HTML 标签综合案例

别让平淡生活&#xff0c;耗尽所有向往 —— 24.4.26 综合案例 —— 一切都会好的 网页制作思路&#xff1a;从上到下&#xff0c;先整体到局部&#xff0c;逐步分析制作 分析内容 ——> 写代码 ——>保存——>刷新浏览器&#xff0c;看效果 <!DOCTYPE html> &l…

ubuntu22 部署fastDFS单节点和集群,整合Spring Boot(刚部署成功)

ubuntu22 部署fastDFS单节点和集群 一、先准备1、所需依赖安装2、下载安装包 二、安装FastDFS单节点1、libfastcommon安装1.1、创建软连接 2、安装fastDFS2.1、fastDFS目录简单介绍2.2、创建软连接 3、配置和启动Tracker服务3.1、修改Tracker配置文件3.2、启动Tracker 4、配置和…

【笔试强训】除2!

登录—专业IT笔试面试备考平台_牛客网牛客网是互联网求职神器&#xff0c;C、Java、前端、产品、运营技能学习/备考/求职题库&#xff0c;在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://ac.nowcoder.com/acm/…

IDEA插件分享 - enum-quick-generate 实现枚举类自动生成

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

代码随想录算法训练营DAY38|C++动态规划Part.1|动态规划理论基础、509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯

文章目录 动态规划理论基础什么是动态规划动态规划的解题步骤DP数组以及下标的含义递推公式DP数组初始化DP数组遍历顺序打印DP数组动态规划五部曲 动态规划应该如何debug 509.斐波那契数什么是斐波那契数列动态规划五部曲确定dp数组下标以及含义确定递推公式dp数组如何初始化确…

数据分析:甲基化分析-从DNA methylation的IDAT文件到CpG site的Beta values

介绍 DNA Methylation和疾病的发生发展存在密切相关&#xff0c;它一般通过CH3替换碱基5‘碳的H原子&#xff0c;进而调控基因的转录。常用的DNA methylation是Illumina Infinium methylation arrays&#xff0c;该芯片有450K和850K&#xff08;也即是EPIC&#xff09;。 该脚…

Mac虚拟机装Windows Mac环境安装Win虚拟机教程 macbookpro安装windows虚拟机

在如今多元的数字时代&#xff0c;我们经常需要在不同的操作系统环境下进行工作和学习。而对于Mac用户来说&#xff0c;有时候需要在自己的电脑上安装Windows操作系统&#xff0c;以体验更多软件及功能&#xff0c;而在Mac安装Windows虚拟机是常用的一种操作。下面就来看看Mac虚…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release&#xff0c;发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

数字身份管理:Facebook如何利用区块链技术?

随着数字化进程的加速&#xff0c;个人身份管理已成为一个关键议题。在这方面&#xff0c;区块链技术正在逐渐展现其巨大潜力。作为全球最大的社交媒体平台&#xff0c;Facebook也在积极探索和应用区块链技术来改进其数字身份管理系统。本文将深入探讨Facebook如何利用区块链技…

VSCODE通过SFTP链接VM进行开发

在vscode插件里面搜索sftp&#xff0c;安装。 安装之后&#xff0c;按ctrlshiftp&#xff0c;找到sftp的config 然后填写刚刚的IP&#xff0c;然后是你的用户名密码 如果是通过密钥链接的话就是这样配置 然后切换到这个sftp的tab里面 然后在你的项目右键&#xff0c;然后选择op…

el-date-picker 禁用时分秒选择(包括禁用下拉框展示)

2024.04.26今天我学习了对el-date-picker进行禁用时分秒&#xff0c; 在使用el-date-picker组件的时候&#xff0c;我们有可能遇到需要把时分秒的时间固定&#xff0c;然后并且不能让他修改&#xff1a; 1714120999296 比如右上角的这个时间&#xff0c;我们要给它固定是‘08:…