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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何正确使用通道来控制并发?相关的知识,希望对你有一定的参考价值。

我是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

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

答案

这里的问题很简单:

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)。

另一答案

还有一种方法可以并行运行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

以上是关于如何正确使用通道来控制并发?的主要内容,如果未能解决你的问题,请参考以下文章

全栈编程系列SpringBoot整合Shiro(含KickoutSessionControlFilter并发在线人数控制以及不生效问题配置启动异常No SecurityManager...)(代码片段

GO语言入门第五节 Go语言的并发编程

如何在并发操作中关闭通道?

go语言学习笔记 — 进阶 — 并发编程:通道(channel) —— 在多个goroutine之间通信的管道

云原生时代崛起的编程语言Go并发编程实战

go语言之并发编程 channel