go实现判断20000数据范围内哪些是素数(只能被1和它本身整除的数),采用多协程和管道实现

实现一个并发程序,用于寻找 20000 以内的所有素数。使用了 Goroutines 和 Channels 来分发和处理任务,并通过 WaitGroup(实现为 exitChan)来同步 Goroutines 的退出。

一.GO代码

package mainimport ("fmt""time"
)// 判断20000数据范围内哪些是素数(只能被1和它本身整除的数) 开启4个协程完成 采用管道同步通信 sync.WaitGroup
// WaitGroup 通常用于当只需要知道一组 Goroutines 何时结束,而不需要它们之间通信的场景
func main() {// 创建用于保存待检查数字的通道intChan := make(chan int, 1000)// 创建用于保存素数结果的通道primeChan := make(chan int, 2000)// 创建用于协调 Goroutines 退出的通道exitChan := make(chan bool, 4) // 协程数量并不是越多越快 根据CPU核数改变充分利用CPU性能// 开始时间 时间戳//startTime := time.Now().Unix()startTime := time.Now()// 开启一个 Goroutine 向 intChan 写入数据go putNum(intChan)// 开启 8 个 Goroutines 从 intChan 读取数据并判断是否为素数for i := 0; i < cap(exitChan); i++ {go primeNum(intChan, primeChan, exitChan)}// 开启一个匿名 Goroutine 等待所有 primeNum Goroutines 完成go func() {for i := 0; i < cap(exitChan); i++ {<-exitChan // 等待每个 primeNum Goroutine 的退出信号}// 结束时间useTime := time.Now().Sub(startTime)fmt.Println("-----------------所用时间:------------------------", useTime) // 所用时间: 3.1556msclose(primeChan)                                                       // 所有 primeNum Goroutines 完成后关闭 primeChan}()for i := 0; i < 10; i++ {go say(i)//time.Sleep(time.Second)}// 从 primeChan 中读取并打印素数结果for {//prime, ok := <-primeChan_, ok := <-primeChanif !ok {break // 如果 primeChan 被关闭,则退出循环}//fmt.Println("素数:", prime)}fmt.Println("主线程退出!!!!!!!!!!")
}// putNum 函数:向 intChan 中写入数字
func putNum(intChan chan int) {for i := 1; i <= 20000; i++ {intChan <- i // 将数字 1 到 20000 写入 intChan}close(intChan) // 写入完成后关闭 intChanfmt.Println("向intChan写入2000条数据完成")
}// primeNum 函数:从 intChan 中读取数字并判断是否为素数
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {for {num, ok := <-intChan // 从 intChan 中读取数据if !ok {fmt.Println("其中一个协程数据处理完毕~~~")break // 如果 intChan 被关闭,则退出循环}// 判断读取的数字是否为素数if isPrime(num) {primeChan <- num // 如果是素数,将其发送到 primeChan}}exitChan <- true // 发送退出信号到 exitChan
}// isPrime 函数:判断一个数是否为素数
/*
假设 n 不是素数,那么它可以表示为两个因子的乘积,即 n = a * b。
如果 a 和 b 都大于 sqrt(n)(n 的平方根),那么 a * b 将大于 n,这与 n = a * b 矛盾。
因此,如果 n 有超过1和它本身以外的因子,它必定至少有一个因子是小于或等于 sqrt(n) 的。
*/
func isPrime(n int) bool {if n == 1 {return false // 1 不是素数}for i := 2; i*i <= n; i++ { //如果一个数不是素数,则它必定有一个因子小于或等于它的平方根。if n%i == 0 {return false // 如果 n 能被除了 1 和它本身以外的数整除,则不是素数}}return true // 如果不能被任何数整除,则是素数
}func say(i int) {defer func() {if e := recover(); e != nil {fmt.Println("eeeeee:", e)}}()if i == 5 {panic("say-------------------i==5 err")}fmt.Printf("协程 %d 执行完毕\n", i)
}

二.管道只读和只写

在 Go 语言中,通道(Channel)是用于在不同的 Goroutines 之间传递数据的一种方式。通道可以是双向的,也可以是单向的。单向通道分为只读和只写通道。这种区分有助于提高程序的类型安全性和清晰性。

1.只读通道(Receive-Only Channel)

只读通道是一种只能从中接收数据的通道。在函数参数中使用只读通道可以确保该函数不会意外地向通道发送数据。

声明只读通道的方式是:<-chan DataType

2.只写通道(Send-Only Channel)

只写通道是一种只能向其发送数据的通道。在函数参数中使用只写通道可以确保该函数不会意外地从通道读取数据。

声明只写通道的方式是:chan<- DataType

3.示例

下面是一个简单的例子,展示了如何使用只读和只写通道:

goCopy codepackage mainimport ("fmt""time"
)// 该函数接收一个只写通道参数,只能向该通道发送数据
func sendOnly(ch chan<- int) {for i := 0; i < 5; i++ {ch <- i}close(ch) // 发送完数据后关闭通道
}// 该函数接收一个只读通道参数,只能从该通道读取数据
func receiveOnly(ch <-chan int) {for v := range ch {fmt.Println("Received:", v)}
}func main() {ch := make(chan int)go sendOnly(ch)       // 启动一个 Goroutine 向通道发送数据receiveOnly(ch)       // 在主 Goroutine 中从通道接收数据fmt.Println("Done")
}

在这个例子中:

  • sendOnly 函数有一个只写通道参数,它向该通道发送一系列整数,然后关闭通道。
  • receiveOnly 函数有一个只读通道参数,它从该通道接收并打印数据,直到通道被关闭。
  • main 函数中,我们创建了一个双向通道 ch,然后启动 sendOnly 函数在一个新的 Goroutine 中运行,并在主 Goroutine 中调用 receiveOnly 函数。
    在这里插入图片描述

三.select的应用介绍

在 Go 语言中,select 语句是一种处理多个通道(Channel)的方式。它可以监听多个通道上的发送和接收操作,并且当任何一个通道准备就绪时,select 就会执行该操作。如果多个通道同时就绪,select 将随机选择一个执行。select 语句是非阻塞的,它可以与 Go 的并发特性结合,实现高效的任务处理和通信。

1.基本语法

select 语句的基本语法如下:

select {
case <-chan1:// 执行通道 chan1 上的接收操作
case chan2 <- value:// 向通道 chan2 发送值 value
default:// 如果以上都没有准备就绪,则执行默认操作
}

2.示例

  • 启动多个协程,每个协程向各自的通道发送数据。

  • 使用 select 语句来接收不同协程的数据,同时监控超时情况和程序结束信号。

    package mainimport ("fmt""math/rand""time"
    )func sendData(ch chan<- int, id int) {for {// 模拟随机的发送间隔time.Sleep(time.Duration(rand.Intn(3)) * time.Second)ch <- id}
    }func main() {rand.Seed(time.Now().UnixNano())// 创建两个通道ch1 := make(chan int)ch2 := make(chan int)// 创建一个超时通道timeout := make(chan bool)// 创建一个结束信号的通道done := make(chan bool)// 启动协程发送数据go sendData(ch1, 1)go sendData(ch2, 2)// 启动一个协程来控制超时go func() {time.Sleep(5 * time.Second) // 设置超时时间为5秒timeout <- true}()// 使用 select 处理不同的情况for {select {case msg := <-ch1:fmt.Printf("Received from ch1: %d\n", msg)case msg := <-ch2:fmt.Printf("Received from ch2: %d\n", msg)case <-timeout:fmt.Println("Operation timed out!")done <- truereturncase <-done:fmt.Println("Program ended!")return}}
    }
    • 有两个数据发送协程,每个协程向其通道 ch1ch2 发送一个唯一的标识符。
    • 设置了一个超时协程,如果在5秒内没有完成操作,则向 timeout 通道发送一个信号。
    • main 函数的 select 语句中,我们监听四种情况:从 ch1 接收数据、从 ch2 接收数据、超时和结束程序。
    • 一旦超时发生,我们向 done 通道发送一个信号并结束程序。

四.recover

在 Go 中,协程(Goroutines)是轻量级的线程,用于并发执行任务。当一个协程因为 panic 而异常中断时,它不会影响其他协程的运行,但是如果 panic 没有被捕获(recover),它会导致整个程序崩溃。因此,在协程中合理使用 recover 是处理 panic 的一种有效方法。每个协程都应该独立地处理它们自己的 panic。这意味着你应该在每个可能产生 panic 的协程中使用 recoverrecover 需要在 defer 函数中使用,因为只有在延迟函数中它才能捕获到协程的 panic。

1.示例

package mainimport ("fmt""time"
)func main() {// 启动多个协程for i := 0; i < 3; i++ {go safeGoroutine(i)}// 等待足够长的时间以确保协程执行time.Sleep(1 * time.Second)fmt.Println("主程序结束")
}func safeGoroutine(id int) {defer func() {if r := recover(); r != nil {fmt.Printf("协程 %d 捕获到 panic: %v\n", id, r)}}()// 这里是协程可能会触发 panic 的地方if id == 1 { // 假设只有 id 为 1 的协程会触发 panicpanic(fmt.Sprintf("协程 %d 发生 panic", id))}fmt.Printf("协程 %d 执行完毕\n", id)
}
  • main 函数启动了 3 个协程。
  • 每个协程都调用了 safeGoroutine 函数,在这个函数中,我们使用 deferrecover 来捕获并处理可能发生的 panic。
  • 如果在协程中发生 panic,recover 会捕获到它,并允许协程优雅地处理 panic,而不是使整个程序崩溃。

2.位置

defer func() { ... }() 放在函数中的最上面是一种最佳实践。

  • 确保覆盖整个函数:defer 放在函数开始处可以确保无论 panic 在函数的哪个部分发生,defer 代码块都将被执行。这意味着,无论是由于哪个操作引发的 panic,都会被 defer 中的 recover 捕获和处理。
  • 防止遗漏 panic: 如果将 defer 放在函数中间或末尾,那么在 defer 之前的代码如果发生了 panic,recover 将无法捕获到这个 panic,因为 defer 语句本身还没有被执行。

2.位置

defer func() { ... }() 放在函数中的最上面是一种最佳实践。

  • 确保覆盖整个函数:defer 放在函数开始处可以确保无论 panic 在函数的哪个部分发生,defer 代码块都将被执行。这意味着,无论是由于哪个操作引发的 panic,都会被 defer 中的 recover 捕获和处理。
  • 防止遗漏 panic: 如果将 defer 放在函数中间或末尾,那么在 defer 之前的代码如果发生了 panic,recover 将无法捕获到这个 panic,因为 defer 语句本身还没有被执行。
  • 逻辑清晰:defer 放在函数开头,可以让读代码的人立即知道这个函数有处理 panic 的逻辑,这使得代码的逻辑更清晰、更易于理解。

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

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

相关文章

Python-基础篇-类与对象/面向对象程序设计-py脚本

面向对象基础 第一个面向对象 class Cat:def eat(self):print("小猫爱吃鱼")def drink(self):print("小猫要喝水")# 创建猫对象 tom Cat()tom.eat() tom.drink()print(tom)addr id(tom) print("%x" % addr)新建两个猫对象 class Cat:def ea…

NAT实验

一&#xff1a;实验要求 二&#xff1a;实验分析 拓扑图 三&#xff1a;实验配置 1&#xff1a;路由器配置 R1配置IP R2配置IP 2&#xff1a;缺省路由 查看路由表 3&#xff1a;端口映射 4&#xff1a;pc、HTTP配置 5:DNS、client配置 四&#xff1a;实验结果 pc可以ping…

三菱plc学习入门(创建属于自己的FB模块)

在现实生活中&#xff0c;往往会需要修改一些属于方便自己的库&#xff0c;1&#xff0c;自己创建的库方便自己使用与查看2&#xff0c;提高自己编程能力&#xff0c;3&#xff0c;保护自己的程序不被外人修改&#xff01;&#xff01;&#xff01;下面就让我来操作一下 导入需…

基于springboot+vue的在线视频教育平台系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

ubuntu系统 vscode 配置c/c++调试环境

文章目录 1.安装插件2.目录结构3.cmake tools配置 1.安装插件 c/c插件 cmake cmake tools插件 2.目录结构 . ├── build ├── CMakeLists.txt ├── demo │ └── main.cpp ├── image.png ├── src │ ├── add.cpp │ └── add.hpp └── vsdebug.…

三角形任意一外角大于不相邻的任意一内角

一.代数证明 ∵ 对与△ A C B 中 ∠ c 外接三角形是 ∠ B C D ∵对与△ACB中∠c外接三角形是∠BCD ∵对与△ACB中∠c外接三角形是∠BCD ∴ ∠ B C D π − ∠ C ∴∠BCD\pi-∠C ∴∠BCDπ−∠C ∵ ∠ A ∠ B ∠ C π ∵∠A∠B∠C\pi ∵∠A∠B∠Cπ ∴ ∠ B C D ∠ A ∠…

开抖音小店需要什么要求?这些硬性条件缺一不可,建议收藏

大家好&#xff0c;我是电商花花。 现在越来越多的人开始将抖音作为创业和商业机会的平台&#xff0c;不少人都开始在抖音上做抖音小店&#xff0c;然后卖货&#xff0c;有货源的买自己的产品&#xff0c;没有货源的做无货源产品&#xff0c;赚取商品的差价。 我们做店也有三…

IO网络4.0

思维导图 tftp上传 #include <myhead.h>#define ERR_LOG(msg) do{\perror(msg);\printf("%d %s %s\n", __LINE__, __func__, __FILE__);\ }while(0)#define PORT 69 #define N 516int do_upload(int sfd, struct sockaddr_in sin);int main(int a…

.NET架构师:全网最全“权限系统”设计剖析

&#x1f3c6;作者&#xff1a;科技、互联网行业优质创作者 &#x1f3c6;专注领域&#xff1a;.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造 &#x1f3c6;欢迎关注我&#xff08;Net数字智慧化基地&#xff09;&#xff0c;里面…

解决Python安装库时出现的Requirement already satisfied问题

uirement already satisfied的问题当我们用pip install 库名时&#xff0c;出现了下面 Requirement already satisfied WARNING: Ignoring invalid distribution -ip 的问题 对于这样的问题&#xff0c;解决办法就是在 pip install 后加 - -target你所要添加的库文件地址(注意…

Python爬虫 - 网易云音乐下载

爬取网易云音乐实战&#xff0c;仅供学习&#xff0c;不可商用&#xff0c;出现问题&#xff0c;概不负责&#xff01; 分为爬取网易云歌单和排行榜单两部分。 因为网页中&#xff0c;只能显示出歌单的前20首歌曲&#xff0c;所以仅支持下载前20首歌曲&#xff08;非VIP音乐&…

SpringCloud GateWay 在全局过滤器中注入OpenFeign网关后无法启动

目录 一、问题 二、原因 1、修改配置 2、添加Lazy注解在client上面 3、启动成功 一、问题 当在gateway的全局过滤器GlobalFilter中注入OpenFeign接口的时候会一直卡在路由中&#xff0c;但是不会进一步&#xff0c;导致启动未成功也未报错失败 2024-01-18 22:06:59.299 I…

开发板通过 Ubuntu/Linux 连接外网

文章目录 开发板通过 Ubuntu/Linux 连接外网概述配置 Ubuntu 系统配置开发板 开发板通过 Ubuntu/Linux 连接外网 概述 如果开发板需要访问外网&#xff0c;可以通过网线将开发板与 Ubuntu 系统连接起来&#xff0c;在 Ubuntu 系统中配置 ip_forward 让 Ubuntu 成为路由器&…

数字创意市场:Web3时代创作者的新机遇

随着Web3时代的崭露头角&#xff0c;数字创意市场正迎来全新的变革和机遇。在这个数字化的时代&#xff0c;创作者们将面对更加开放、去中心化的创作和交易环境。本文将深入探讨Web3时代数字创意市场为创作者带来的新机遇&#xff0c;以及这个时代为创意产业带来的变革。 创作者…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-4 label

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>label</title> </head><body> 性别: <label for"male">男</label> <input type"radio" name"sex&quo…

滚动菜单ListView

activity_main.xml <include layout"layout/title"/> 引用上章自定义标题栏 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app&qu…

配置云服务器

需求 我打算配置一个小型云服务器&#xff0c;玩玩。学习怎么部署网站等等。 1、购买云服务器 第一次玩&#xff0c;我购买的华为云提供的云服务器 66元 安装ubuntu 22 2、配置环境 jdk 解压jdk命令 tar -xzf jdk-8u171-linux-x64.tar.gz 修改配置文件 vim /etc/profil…

如何安装“虚拟机(VMware)”win10系统?

1、 下载 vmware官网下载&#xff1a;vmware官网跳转 2、 安装

HarmonyOS NEXT鸿蒙星河版发布

1月18日,在深圳举行的“鸿蒙生态千帆启航仪式”上,华为常务董事、终端BG CEO余承东宣布HarmonyOS NEXT鸿蒙星河版面向开发者开放申请。鸿蒙星河版将实现原生精致、原生易用、原生流畅、原生安全、原生智能、原生互联6大极致原生体验。 并且,华为在 1 月 15 日开启了HarmonyO…

SpringBoot SaToken Filter如用使用ControllerAdvice统一异常拦截

其实所有的Filter都是一样的原理 大致流程: 创建一个自定义Filter, 用于拦截所有异常此Filter正常进行后续Filter调用当调用后续Filter时, 如果发生异常, 则委托给HandlerExceptionResolver进行后续处理即可 以sa-token的SaServletFilter为例 首先注册SaToken的过滤器 pac…