You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Go并发素数筛中prime := <-ch先于go Filter()执行的疑问

解答Go并发素数筛的通道数据流动疑问

这是个非常好的问题,刚好戳中了Go并发模型里通道阻塞特性和goroutine调度的核心逻辑,咱们一步步拆解这个素数筛的执行流程,你就能明白为什么Filter能拿到数据了。

先明确核心前提:Go通道的同步阻塞特性

在Go里,通道的<-操作是同步且阻塞的:

  • 当你执行ch <- x时,发送方会暂停,直到有接收方准备好接收这个值;
  • 当你执行x := <-ch时,接收方会暂停,直到通道里有数据可以接收。

这个特性是整个并发素数筛能正常工作的基础。

逐步骤拆解代码执行流程

咱们从主函数的第一次循环开始,跟着数据流动走:

  1. 初始启动与第一个素数的获取

    • 主函数创建初始通道ch,启动go Generate(ch)。Generate函数立刻开始执行,i=2时执行ch <- 2,但此时没有接收方,Generate会阻塞在这里。
    • 主函数进入循环,执行prime := <-ch,接收了通道里的2——这时候Generate的阻塞解除,立刻继续执行i=3,并尝试ch <- 3,但此时还没有其他接收方,Generate又一次阻塞。
  2. Filter goroutine的启动与数据接收

    • 主函数打印完2,创建新通道ch1,启动go Filter(ch, ch1, prime)(这里prime是2)。
    • Filter goroutine启动后,第一行代码就是num := <-in(in就是原来的ch),这时候它会尝试接收通道里的3——刚好Generate之前阻塞在ch <-3,现在有了接收方,Generate的阻塞解除,继续生成下一个数字4,执行ch <-4后再次阻塞。
  3. Filter的过滤与数据传递

    • Filter拿到3后,检查3 % 2 != 0,于是执行out <-3(out是ch1),但此时ch1还没有接收方,Filter会阻塞在这里。
    • 主函数执行ch = ch1,回到循环开头,执行prime := <-ch,接收ch1里的3——Filter的阻塞解除,继续执行下一轮num := <-in,接收Generate发的4。
    • Filter检查4%2 ==0,直接跳过,不往ch1发送,然后继续执行num := <-in,等待Generate的下一个数字。
  4. 后续循环的逻辑复用

    • 接下来的流程和上面完全一致:Generate持续生成数字,每个数字都会被对应的Filter接收、过滤,只有不能被当前素数整除的数字才会传递到下一层通道,最终被主函数接收并打印为新的素数。

解答你的核心疑问

你担心prime := <-ch在go Filter()之前,会把通道里的所有数据都取走,但实际上:

  • 主函数只接收一个素数就会切换到新的通道(ch = ch1),后续不会再从原来的通道接收数据;
  • Generate是持续生成新数字的,主函数接收第一个素数后,Generate立刻会把下一个数字发送到原通道,而Filter启动后会立刻从原通道接收这个数字(以及后续的数字);
  • 通道的阻塞特性保证了数据不会“丢失”或“被抢”,每个发送操作都会匹配到对应的接收操作——要么是主函数的第一次接收,要么是Filter的接收。

举个简单的例子:主函数拿走了2,Generate立刻把3塞到原通道,这时候Filter刚好启动,就会把3拿走并处理,主函数接下来只会从新通道拿3,不会再碰原通道的后续数字(比如4、5等)。


内容的提问来源于stack exchange,提问作者offvw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:58:32