Go语言利用Channel和Goroutine并发统计素数的实现

小林子
小林子
发布时间:2026-10-13| 5人浏览过
原创

本文将演示如何在Go语言中利用goroutine和channel的并发机制,高效地统计指定范围内(如1至20000)的所有素数。通过解析数据分发、多协程并行计算及安全退出的流程,提供清晰的代码实现与原理说明。

需求分析

在处理大量数据的计算任务时,串行处理往往效率低下。本例的目标是找出 1 到 20000 之间的所有素数。传统的做法是使用单个循环逐一判断,但在现代CPU的多核特性下,我们可以通过并发的方式将任务拆分给多个协程并行处理,从而显著缩短执行时间。

核心思路图解

整个系统由三个主要的通信管道(Channel)串联而成,具体逻辑如下:

上述流程图展示了经典的"生产者-消费者"模式在并发计算中的变体。我们需要管理好数据的流向以及各个协程的生命周期。

代码实现

为了实现这一功能,我们需要定义三个通道:intChan用于传入数字,primeChan用于传出素数,exitChan用于控制程序的正常退出。以下是完整的实现代码:

package main

import (
	"fmt"
	"time"
)

// putNum: 负责向 intChan 发送 1 到 20000 的数字,完成后关闭通道
func putNum(intChan chan int) {
	for i := 1; i <= 20000; i++ {
		intChan <- i
	}
	close(intChan) // 重要:必须关闭,否则消费者协程会阻塞等待
}

// primeNum1: 从 intChan 读取数字,判断是否为素数,若是则放入 primeChan
// exitChan 用于通知主程序当前协程已完成任务
func primeNum1(intChan chan int, primeChan chan int, exitChan chan bool) {
	var flag bool
	for {
		// 模拟一定延迟以观察并发效果(实际优化中可移除sleep)
		time.Sleep(time.Millisecond * 10)
		
		// 尝试从 intChan 获取数据,ok 为 false 表示通道已关闭且无数据
		num, ok := <- intChan
		if !ok {
			break // 数据取完,当前协程退出
		}

		flag = true // 假设是素数
		// 判断 num 是否为素数
		for i := 2; i < num; i++ {
			if num % i == 0 {
				flag = false // 不是素数
				break
			}
		}
		if flag {
			primeChan <- num // 将素数写入结果通道
		}
	}
	fmt.Println("有一个 prineNum 协程因为取不到数据,退出")
	// 不能在这里直接关闭 primeChan,因为有其他协程也在往里面写
	exitChan <- true // 告知主线程,我这个协程跑完了
}

func main() {
	// 初始化通道
	var intChan chan int = make(chan int, 1000)
	var primeChan chan int = make(chan int, 2000)
	var exitChan = make(chan bool, 4) // 限制只能存4个布尔值

	// 1. 开启一个协程,负责生产 1-20000 的数据
	go putNum(intChan)

	// 2. 开启4个协程,负责消费数据并筛选素数
	for i := 0; i < 4; i++ {
		go primeNum1(intChan, primeChan, exitChan)
	}

	// 3. 监控退出状态:当4个消费者都完成后,关闭结果通道
	go func() {
		for i := 0; i < 4; i++ {
			<-exitChan // 阻塞等待每个协程完成信号
		}
		close(primeChan) // 安全关闭素数通道
	}()

	// 4. 主线程遍历结果通道,打印素数
	for {
		res, ok := <- primeChan
		if !ok {
			break // 结果通道关闭,结束遍历
		}
		fmt.Printf("素数=%d\n", res)
	}
	fmt.Println("main线程退出")
}

关键点解析

上述代码虽然简单,但包含了Go并发编程的几个核心要点:

  1. 通道的生命周期管理: putNum必须在数据写入完毕后调用 close(intChan),否则接收方的 <- intChan 操作将永远处于阻塞状态(死锁)。
  2. 安全的停止信号: 多个协程同时往 primeChan 写数据,因此不能在任意一个协程结束时直接关闭该通道,否则会引发 panic。我们引入了 exitChan 作为协调器,确保只有在所有消费者(Producer of Primes)都结束后,才由专门的监控协程关闭最终的结果通道。
  3. 并发度控制: 代码中开启了4个处理协程,这个数字可以根据CPU的核心数和任务的复杂度进行调整,以达到最优性能。

结论

通过本例可以看出,利用Go语言的goroutine和channel,可以轻松实现高并发的数据处理任务。在不需要复杂的锁机制的情况下,就能实现线程安全的数据传递与状态同步,这是Go语言在处理此类计算密集型任务时的显著优势。

以上就是利用Channel和Goroutine并发统计素数的详细内容,更多关于Go并发编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。