如何正确使用通道来控制并发?

问题描述 投票:1回答:2

我是Go的并发新手,我正试图弄清楚如何使用通道来控制并发。我想做的是有一个循环,我可以使用一个新的go例程调用一个函数,并在该函数处理时继续循环,我想限制运行到3的例程的数量。我的第一次尝试这样做是下面的代码:

func write(val int, ch chan bool) {
    fmt.Println("Processing:", val)
    time.Sleep(2 * time.Second)
    ch <- val % 3 == 0
}

func main() {
    ch := make(chan bool, 3) // limit to 3 routines?
    for i := 0; i< 10; i++ {
        go write(i, ch)
        resp := <- ch
        fmt.Println("Divisible by 3:", resp)
    }
    time.Sleep(20 * time.Second)
}

我的印象是,这基本上会一次调用write 3,然后继续处理下一个3,直到前3个完成。根据记录的内容,它似乎只是一次处理一个。代码可以是found and executed here

在此示例中,我需要更改哪些内容才能获得上述功能?

go concurrency
2个回答
2
投票

这里的问题很简单:

for i := 0; i< 10; i++ {
    go write(i, ch)
    resp := <- ch
    fmt.Println("Divisible by 3:", resp)
}

你旋转一个goroutine,然后等待它响应,然后继续循环并旋转下一个goroutine。它们不能并行运行,因为您从不同时运行其中两个。

要解决这个问题,你需要启动所有10个goroutine,然后等待所有10个响应(playground):

for i := 0; i< 10; i++ {
    go write(i, ch)
}
for i := 0; i<10; i++ {
    resp := <- ch
    fmt.Println("Divisible by 3:", resp)
}

现在你在频道上有7个goroutines阻塞 - 但它很简短,你看不到它发生,所以输出不会很有趣。如果您尝试在goroutine的末尾添加Processed消息,并在每个通道读取之间休眠,您将看到其中3个立即完成(好,等待2秒后),然后其他人解锁并逐个完成(playground)。


0
投票

还有一种方法可以并行运行go例程,等待所有这些例程使用Wait groups返回通道上的值。它还有助于同步go例程。如果您正在使用go例程等待所有这些例程在执行另一个函数之前完成更好的方法是使用wait group

package main

import (
    "fmt"
    "time"
    "sync"
)

func write(val int, wg *sync.WaitGroup, ch chan bool) {
    defer wg.Done()
    fmt.Println("Processing:", val)
    time.Sleep(2 * time.Second)
    ch <- val % 3 == 0
}
func main() {
    wg := &sync.WaitGroup{}
    ch := make(chan bool, 3)
    for i := 0; i< 10; i++ {
        wg.Add(1)
        go write(i, wg, ch)
    }
    for i := 0; i< 10; i++ {
        fmt.Println("Divisible by 3: ", <-ch)
    }
    close(ch)
    wg.Wait()
    time.Sleep(20 * time.Second)
}

Playground example

© www.soinside.com 2019 - 2024. All rights reserved.