Golang Daisy-chain(菊花链)分析
时间:2021-08-12
本文章向大家介绍Golang Daisy-chain(菊花链)分析,主要包括Golang Daisy-chain(菊花链)分析使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在学习 go 并发的过程中,意外看到了菊花链的代码,一开始基本上对于整体流程摸不着头脑,经过查阅资料和自己苦思,最终找到了两个关键点,捋清了整个执行过程
代码:
func TestFunc5(t *testing.T) {
/*
* 利用信道菊花链筛法求某一个整数范围的素数
* 筛法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列,
* 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。
* 依次类推,直到筛子为空时结束
*/
const max = 100 // 找出100以内的所有素数
nums := xrange() // 初始化一个整数生成器
number := <-nums // 从生成器中抓一个整数(2), 作为初始化整数
for number <= max { // number作为筛子,当筛子超过max的时候结束筛选
fmt.Println(number) // 打印素数, 筛子即一个素数
nums = filter(nums, number) //筛掉number的倍数
number = <-nums // 更新筛子
}
}
func filter(in chan int, number int) chan int {
// 输入一个整数队列,筛出是number倍数的, 不是number的倍数的放入输出队列
// in: 输入队列
out := make(chan int)
go func() {
for {
i := <-in // 从输入中取一个
if i%number != 0 {
out <- i // 放入输出信道
}
}
}()
return out
}
func xrange() chan int { // 从2开始自增的整数生成器
var ch chan int = make(chan int)
go func() { // 开出一个goroutine
for i := 2; ; i++ {
ch <- i // 直到信道索要数据,才把i添加进信道
}
}()
return ch
}
代码是从网络上复制,然后放在本地测试文件中进行调试的,自己运行的话可以把 TestFunc 改成 main
对于菊花链的代码,从逻辑上来说并不复杂:
- 采用的是埃式筛,将 2-n 的整数按照从小到大的顺序排列,以 2 为开始的素数,3/2 不能整除是素数,5/2 且 5/3 不能整除是素数,以此类推,不断从小到大除以已经得出的素数,都不能整除,意味着它没有可因式分解的余地,也就是素数;代码也有改进的空间,即使用欧式筛,去除不必要的筛选(这个我还没研究,感兴趣的可以自己看看);
对于菊花链,对我个人而言,最关键的两个点在于:
- filter 中所有的 goroutine 都是一直存在的;
- filter 中不断建立 out,而 out 又通过 return 返回给 nums,nums 再通过 filter 传参给 in;最终效果也就是每个 goroutine 中都建立了一个新的 channel,而这个 channel 都会依次传递给下一个 goroutine,也就是第一个的 out 第二个 in 接收,第二个的第三个接收等等,等到所有的 goroutine 依次执行完后,最后一个 goroutine 才会获取到真正想要的那个 out,然后返回给 nums;
下面即是我捋出来的整个执行过程:
- 通过 xrange 初始化一个 channel nums,接下来依次接收 从 2 开始不断自增 1 的整数,将作为被筛选的数;
- number 初始化中 nums 中获取 2;
- 开始循环筛选 2-max 中的素数,并首先输出初始素数 2;
nums = filter(nums, number)
将 xrange channel 和 2 传递给 filter;- filter 中创建一个 out channel,生成一个 goroutine;
- goroutine 中,i 从 xrange channel 也就是 in 中获取到 2 的自增一 3;
- number1 = 2,3%2 不能整除,素数,放入 out,return out;
nums = out
,然后number = <- nums
更新 number 为 3;- 循环输出,继续调用 filter,这时候传入 nums 也就是 out1 和 number 3;
- filter 新建 out2,生成 goroutine2,从 out1(in)中读取,没有数值,堵塞;
- goroutine1 out1 值被消费,继续运行,从 xrange(in)中读取 4,number1 = 2,4%2 整除 pass,5%2 不能整除,输出到 out1,阻塞;
- goroutine2 从 out1(in)中顺利读取到值 5,继续运行,number2 = 3,5%3 不能整除,素数,输出到 out2,return;
- ………………
- 依次类推,从 goroutine1 开始,不断固定的筛掉 2 的倍数、3 的倍数等等,新的 in 不断阻塞从头筛选获取;在这个过程中,out 本身形成了一个链条,goroutine 的排序运行让整个链条顺利运行;
- 最终不断从 xrange 中获取到超于一百的素数,return 之后判定结束运行。
值得注意的是:in2 获取了 out1,让 out1 不再阻塞,能够继续运行,但是最终还是会阻塞在输出处 out1,直到最新的 out return,并再次调用 filter。也就是说它们的执行顺序并不一直是我上面说的每次都按照顺序执行,只是最终呈现的结果是顺序的,并且逻辑上没有问题
两个关键点卡住了我很长时间,第一点很基础但一时忽略了,而第二点尤为重要,让我对整个执行过程总是隔着一层雾。还是需要更多的学习与实践,记录下分析结果,与君共勉。
原文地址:https://www.cnblogs.com/saryta/p/15131945.html
- Thrift抛直接内存OOM一点解决思路
- 小顶堆Java实现
- Tomcat源码分析一:源码导入
- 如何使用Metasploit对安卓手机进行控制
- 关于MySQL DNS解析探究之二:unauthenticated user
- Thrift Direct Memory OOM问题解决方法
- Mapreduce程序中reduce的Iterable参数迭代出是同一个对象
- 内部威胁那些事儿(二):系统破坏
- 从用户行为去理解内容-item2vec及其应用
- Dubbo与Zookeeper、SpringMVC整合和使用(入门级)
- Websocket HandShake Sec-WebSocket-Accept 生成策略
- 关于JVM CPU资源占用过高的问题排查
- ActiveMQ简单介绍以及安装
- Java Process destroy方法kill进程,返回码测试
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android实现向本地写入一个XML文件和解析XML文件
- Android自定义View实现带4圆角或者2圆角的效果
- Android 在 res/layout 文件夹 下创建一个 子文件夹实例
- Android开发实现TextView超链接5种方式源码实例
- Android根据包名停止其他应用程序的方法
- Android APP存活检测方式
- 利用Android两行代码真正杀死你的App
- android判断应用是否已经启动的实例
- 解决android studio引用远程仓库下载慢(JCenter下载慢)
- 在Android中查看当前Activity是否销毁的操作
- Android 7.0 运行时权限弹窗问题的解决
- Android加密之全盘加密详解
- Android 实现彻底退出自己APP 并杀掉所有相关的进程
- 使用Android开发接入第三方原生SDK实现微信登录
- Android打包篇:Android Studio将代码打包成jar包教程