新手问一个 go 实现并发素数筛的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
RoccoShi

新手问一个 go 实现并发素数筛的问题

  •  
  •   RoccoShi 2024 年 10 月 29 日 1983 次点击
    这是一个创建于 542 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func Filter(in <-chan int, out chan<- int, prime int) { for { i := <-in if i%prime != 0 { out <- i } } } func Generate(ch chan<- int) { for i := 2; ; i++ { ch <- i } } func main() { ch := make(chan int) go Generate(ch) // print the first 10 prime numbers for i := 0; i < 10; i++ { prime := <-ch println("next prime = ", prime) ch1 := make(chan int) go Filter(ch, ch1, prime) ch = ch1 } } 

    func Filter(in <-chan int, out chan<- int, prime int) { for { i := <-in if i%prime != 0 { out <- i } } } func main() { ch := make(chan int) go func() { for i := 2; ; i++ { ch <- i } }() for i := 0; i < 10; i++ { prime := <-ch println("next prime = ", prime) ch1 := make(chan int) go Filter(ch, ch1, prime) ch = ch1 } } 

    运行后发现上面的代码可以实现并发素数筛的功能, 但是下面的闭包写法就不行, 有没有大佬解释一下?

    9 条回复    2024-10-30 22:16:50 +08:00
    kkk9
        1
    kkk9  
       2024 年 10 月 29 日
    func Filter(in int, out int, prime int) PLEASE!!!
    hingle
        2
    hingle  
       2024 年 10 月 29 日
    go func(ch chan<- int) {
    for i := 2; ; i++ {
    ch <- i
    }
    }(ch)
    mainjzb
        3
    mainjzb  
       2024 年 10 月 29 日
    ch = ch1
    这行导致的

    。。这写法
    RoccoShi
        4
    RoccoShi  
    OP
       2024 年 10 月 29 日
    @hingle 这样确实是可以的, 但是我想问的其实是原来错误的写法里, 闭包内部的这个 ch 的生命周期到底是什么样的
    RoccoShi
        5
    RoccoShi  
    OP
       2024 年 10 月 29 日
    顺便说一下, 源代码来自 rob pike 的一次分享:
    &t=821s

    以及可以在 reddit 上的这个回答查看正确版本的详细数据流分析: https://www.reddit.com/r/golang/comments/434zry/help_understanding_this_prime_sieve_concurrent/
    grzhan
        6
    grzhan  
       2024 年 10 月 30 日   1
    这应该单纯是个闭包问题:

    1. ch 变量本质上是个 *hchan ( https://github.com/golang/go/blob/ed035af7b7d7c1cd2e6f852e22a9b04fc2a2cc65/src/runtime/chan.go#L34 ),是指向 make(chan int) 也就是 runtime.makechan 创建的 hchan 的指针。

    2. 直接使用闭包引用 ch ,ch 发生了内存逃逸(因为是 go func ,我 -gcflags="-m" 看了下确实逃逸到了堆),你在闭包 go func 中使用 ch ,就是在操作 ch 指向的 hchan 。

    3. main 函数后续 ch = ch1 , 也就是 ch 指向了原本 ch1 指向的 hchan ,导致 go func 操作的 hchan 也发生了变化,进而整体程序没有按照预期执行。

    4. 而正确的实现 Generate(ch),以及 func(ch){...}(ch) ,是函数传参,是将 ch 变量值复制传入到了 Generate 或者 go func 里。

    如果你去看汇编,这次 ch 就分配在栈里( main.ch+40(SP) ),在运行 go func 之前就把它的值复制到寄存器里供函数使用了 ( MOVQ main.ch+40(SP), CX )。因此后续 main 里 ch 针对 hchan 的指向发生变化不会影响 go func 内部,值复制保证 go func 内部指向的 hchan 不变。


    感兴趣自己可以看下汇编研究下,我也只是大致看了下:go tool compile -S main.go > assembly.s
    RoccoShi
        7
    RoccoShi  
    OP
       2024 年 10 月 30 日 via iPhone
    @grzhan 解释的很清楚
    grzhan
        8
    grzhan  
       2024 年 10 月 30 日   2
    说起来这个 Rob Pike 的素数筛法应该思路就是当年 CSP 1978 这篇论文提到的素数算法,以前欧长坤老板做过 CSP 1978 论文解读的分享,里面就有素数筛法的例子,论文当然是自己的 CSP 语言,而他写了个 Go 版本:
    https://github.com/changkun/pkg/blob/f787593b4467793f8ee0b07583ea9ffde5adf2be/csp/csp.go#L833
    kingcanfish
        9
    kingcanfish  
       2024 年 10 月 30 日   2
    @grzhan #8 https://swtch.com/~rsc/thread/ 补充下 Russ Cox 的文章 顺便提一嘴 xv6 有个实验就是实现这样的素数筛
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1000 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 22:59 PVG 06:59 LAX 15:59 JFK 18:59
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86