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 = 1
	for i := 1; i <= n; i++ {
		sum *= int64(i)
	}
	m[n] = sum
	wg.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 = 1
	for i := 1; i <= n; i++ {
		sum *= int64(i)
	}
	m[n] = sum
	wg.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 = 1
	for i := 1; i <= n; i++ {
		sum *= int64(i)
	}
	ch <- [2]int64{int64(n), sum}
	wg.Done()
	// 关闭channel
	if 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]int
	a["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)
	<-done
	seconds := 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 <- n
	fmt.Println(n)
	return true
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络原理】TCP协议的连接管理机制(三次握手和四次挥手)

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

SkyWalking 自定义Span并接入告警

图容易被CSDN吞掉&#xff0c;我在掘金也发了&#xff1a;https://juejin.cn/post/7361821913398837248 我就是这么膨胀 最近在做 OpenAI API 套壳&#xff0c;当我使用 okhttp-sse 这个库进行流式内容转发的时候&#xff0c;我发现有些回调方法 SkyWalking 不能抓取到。这就…

JS面试题汇总(十)

JavaScript 的数据对象有那些属性值&#xff1f; writable&#xff1a;这个属性的值是否可以改。 configurable&#xff1a;这个属性的配置是否可以删除&#xff0c;修改。 enumerable&#xff1a;这个属性是否能在 for…in 循环中遍历出来或在 Object. keys 中列举出来。 …

小程序评分/关键词/UV优化助力小程序登顶

随着小程序市场的日益繁荣&#xff0c;小程序搜索排名优化成为了众多开发者关注的焦点。小程序搜索排名被很多因素影响着&#xff0c;关键词、评分还有uv&#xff08;授权&#xff09;等。在本文小柚和各位老板分享如何有效优化小程序搜索排名的经验。 一、关键词策略 关键词是…

[最新]CentOS7设置开机自启动Hadoop集群

安装好Hadoop后我们可以使用开机自启动的方式&#xff0c;节约敲命令的时间。注意是centOS7版本!!!和centOS6版本区别非常大!!! 1、切换到系统目录 [rootmaster ~]# cd /etc/systemd [rootmaster systemd]# ll total 32 -rw-r--r-- 1 root root 720 Jun 30 23:11 bootcha…

汽车新智能图谱里:理解腾讯的AI TO B路径

将自身的C2B产品和产业理解充分AI化&#xff0c;在自身内部场景率先验证跑通后&#xff0c;进而释放给产业伙伴&#xff0c;对应到具体的需求痛点&#xff0c;一起打磨对应的行业AI模型。 这也恰是腾讯“实用”标签背后的AI产业路径。 作者|皮爷 出品|产业家 成本、性价…

DS进阶:并查集

一、并查集的原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这…

Taro +vue3 中实现全局颜色css变量的设置和使用

当我们现在需要弄一个随时修改的页面颜色主题色 我们可以随时修改 我使用的是 Taro 框架 一般有一个app.less 文件 我们在这个里面 设置一个root 全局样式 :root {--primary-color: #028fd4;--secondary-color: #028fd6;/* 添加其他颜色变量 */ } 这样在全局我们就可以使用这…

uniapp 微信小程序 分享海报的实现

主页面 <template><view class"page"><!-- 自定义导航栏--><Navbar title"我的海报"></Navbar><view class"container"><poster ref"poster" :imageUrl"image" :imageWidth"7…

python之List列表

1. 高级数据类型 Python中的数据类型可以分为&#xff1a;数字型&#xff08;基本数据类型&#xff09;和非数字型&#xff08;高级数据类型&#xff09; 数字型包含&#xff1a;整型int、浮点型float、布尔型bool、复数型complex 非数字型包含&#xff1a;字符串str、列表l…

探索和构建 LLaMA 3 架构:深入探讨组件、编码和推理技术(四)分组多查询注意力

探索和构建 LLaMA 3 架构&#xff1a;深入探讨组件、编码和推理技术&#xff08;四&#xff09;分组多查询注意力 Grouped-query Attention&#xff0c;简称GQA 分组查询注意力&#xff08;Grouped-query Attention&#xff0c;简称GQA&#xff09;是多查询和多头注意力的插值…

【35分钟掌握金融风控策略10】风控策略部署2

目录 策略部署 决策引擎系统简介 基于决策引擎进行策略部署 策略部署结果验证 知识点补充 测试验证 回溯比对 策略部署 策略主要部署在决策引擎上进行风险决策&#xff0c;接下来分别介绍决策引擎系统&#xff0c;以及基于决策引擎进行策略部署的相关内容。 决策引擎系…

java-Spring-(MyBatis框架-xml管理)

目录 前置条件 xml与注解比较 1.1 xml定义 1.2 和SQL注解比较 建包准备 插入数据 ​编辑 更新数据 删除数据 查询数据 查看单字段查询 &#x1f3f7;&#x1f4a3;前置条件 创建一个spring boot 初始化的项目 &#x1f3f7;&#x1f4a3;xml与注解比较 1.1 xml定义 …

微信小程序简单实现购物车功能

微信小程序简单实现购物车结算和购物车列表展示功能 实现在微信小程序中对每一个购物车界面的商品订单&#xff0c;进行勾选结算和取消结算的功能&#xff0c;相关界面截图如下&#xff1a; 具体实现示例代码为&#xff1a; 1、js代码&#xff1a; Page({/*** 页面的初始数…

SpringCloudAlibaba:2.1nacos

概述 概述 简介 Nacos是阿里巴巴开源的服务注册中心以及配置中心 Nacos注册中心Eureka 服务配置Config 服务总线Bus 官网 Nacos官网 | Nacos 官方社区 | Nacos 下载 | Nacos 名字由来 Naming&#xff1a;名字 Configurations&#xff1a;配置 Service&#xff1a;服务 功能…

【基础篇】Git 基础命令与核心概念

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 一&#xff0c;Git 初识 1.1&#xff0c;问题引入 不知道你工作或学习时&#xff0c;有没有遇到…

Centos8操作系统安装mysql5.7版本以及报错解决

目录 一、卸载MySql 1.首先查看已安装的mysql 2.逐个或者执行一下命令统一卸载掉 注意&#xff1a; 3. 卸载其他相关文件 二、安装MySql 1.安装mysql的rpm源 2.安装MySql 如果遇到以下错误&#xff1a; 问题一: 解决方法&#xff1a; 问题二、 解决方法&#xff1…

国产麒麟v10系统下打包electron+vue程序,报错unknown output format set

报错如下&#xff1a; 报错第一时间想到可能是代码配置原因报错&#xff0c;查看代码似乎感觉没啥问题 又查看具体报错原因可能是因为icon的原因报错&#xff0c;后面查阅发现ico在各系统平台会不兼容&#xff0c;也就是ico是给win下使用的&#xff0c;此处改下图标格式就ok&am…

1、Qt简介

文章目录 前言一、pySide2 / pySide6 ,PyQt5 / PyQt6二、安装包1 安装pyside22 安装pyqt5三、从一个简单的例子开始三、界面动作处理---信号(signal)与槽(slot)(Qt最核心的机制)--- 绑定事件封装到类中总结前言 参考文章:Qt简介 本文开始就开始进入到qt的开发笔记书写…

【论文解读】QUEST: Query Stream for Practical Cooperative Perception

QUEST 摘要引言QUERY COOPERATION PARADIGMQUEST FRAMEWORKA. Overall ArchitectureB. Cross-agent Query Interaction 实验结论 摘要 合作感知通过提供额外的视点和扩展感知领域&#xff0c;可以有效地提高个体感知性能。现有的合作模式要么是可解释的(结果合作)&#xff0c;…
最新文章