缓冲区为空后关闭“worker”go 例程

2023-11-29

我想要我的 goroutine 工作人员(ProcessToDo()在下面的代码中)等待所有“排队”工作处理完毕后再关闭。

工作例程有一个“待办事项”通道(缓冲),通过该通道将工作发送给它。它有一个“完成”通道来告诉它开始关闭。文档称,如果满足多个选择,通道上的选择将选择一个“伪随机值”...这意味着在所有缓冲工作完成之前将触发关闭(返回)。

在下面的代码示例中,我希望打印所有 20 条消息...

package main

import (
    "time"
    "fmt"
)


func ProcessToDo(done chan struct{}, todo chan string) {
    for {
        select {
        case work, ok := <-todo:
            if !ok {
                fmt.Printf("Shutting down ProcessToDo - todo channel closed!\n")
                return
            }
            fmt.Printf("todo: %q\n", work)
            time.Sleep(100 * time.Millisecond)
        case _, ok := <-done:
            if ok {
                fmt.Printf("Shutting down ProcessToDo - done message received!\n")
            } else {
                fmt.Printf("Shutting down ProcessToDo - done channel closed!\n")
            }
            close(todo)
            return
        }
    }
}

func main() {

    done := make(chan struct{})
    todo := make(chan string, 100)

    go ProcessToDo(done, todo)

    for i := 0; i < 20; i++ {
        todo <- fmt.Sprintf("Message %02d", i)
    }

    fmt.Println("*** all messages queued ***")
    time.Sleep(1 * time.Second)
    close(done)
    time.Sleep(4 * time.Second)
}

done在您的情况下,通道是完全不必要的,因为您可以通过关闭来发出关闭信号todo频道本身。

并使用for range在通道上,它将迭代直到通道关闭并且其缓冲区为空。

你应该有一个done通道,但只是为了让 goroutine 本身可以发出它已完成工作的信号,以便主 goroutine 可以继续或退出。

这个变体与你的相同,更简单并且不需要time.Sleep()调用等待其他 goroutine(无论如何这都太错误且不确定)。尝试一下去游乐场:

func ProcessToDo(done chan struct{}, todo chan string) {
    for work := range todo {
        fmt.Printf("todo: %q\n", work)
        time.Sleep(100 * time.Millisecond)
    }
    fmt.Printf("Shutting down ProcessToDo - todo channel closed!\n")
    done <- struct{}{} // Signal that we processed all jobs
}

func main() {
    done := make(chan struct{})
    todo := make(chan string, 100)

    go ProcessToDo(done, todo)

    for i := 0; i < 20; i++ {
        todo <- fmt.Sprintf("Message %02d", i)
    }

    fmt.Println("*** all messages queued ***")
    close(todo)
    <-done // Wait until the other goroutine finishes all jobs
}

另请注意,工作协程应使用以下方式发出完成信号:defer因此,如果worker以某种意外的方式返回,或者出现恐慌,主goroutine不会陷入等待worker的状态。所以它应该这样开始:

defer func() {
    done <- struct{}{} // Signal that we processed all jobs
}()

您还可以使用sync.WaitGroup将主 goroutine 同步到工作线程(等待它)。事实上,如果您计划使用多个工作协程,那么这比从done渠道。而且用以下命令来表示完成也更简单WaitGroup因为它有一个Done()方法(这是一个函数调用),所以你不需要匿名函数:

defer wg.Done()

See 吉姆博的回答完整的例子WaitGroup.

使用for range如果您想使用多个工作协程,这也是惯用的:通道是同步的,因此您不需要任何额外的代码来同步对todo频道或从中收到的作业。如果你关闭todo频道中的main(),这将正确地向所有工作协程发出信号。当然,所有排队的作业都会被接收并处理一次。

现在采用使用的变体WaitGroup让主 Goroutine 等待工人(JimB 的回答):如果你想要超过 1 个工人 Goroutine 怎么办?同时处理您的工作(并且很可能是并行的)?

您需要在代码中添加/更改的唯一内容是:要真正启动其中多个:

for i := 0; i < 10; i++ {
    wg.Add(1)
    go ProcessToDo(todo)
}

无需更改任何其他内容,您现在就有了一个正确的并发应用程序,它使用 10 个并发 goroutine 接收并处理您的作业。而且我们没有使用任何“丑陋”的东西time.Sleep()(我们使用了一个,但只是为了模拟缓慢的处理,而不是等待其他 goroutine),并且您不需要任何额外的同步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

缓冲区为空后关闭“worker”go 例程 的相关文章

  • 从 Go Slice 中选择一个随机值

    情况 我有一些值 需要从中随机选择一个值 然后我想将它与固定字符串连接起来 到目前为止 这是我的代码 func main create the reasons slice and append reasons to it reasons m
  • Java 中具有可重入锁和条件的生产者消费者场景

    我使用可重入锁和条件编写了一个生产者消费者程序 它工作正常 但我不太确定实施是否正确 此外 它似乎不是最佳的 有人可以验证这是否是正确的实现 此外您能告诉我如何优化它 比如 在真正需要的地方锁定 public class TestRL st
  • Bash脚本无法执行Go命令

    我正在尝试编写一个 bash 脚本来自动在不同的目录中运行 go get install 相关部分在这里 cd web go get cd web go install cd services go get cd services go i
  • runtime.LockOSThread 是否允许子 goroutine 在同一个操作系统线程中运行?

    我明白在 Go 中 runtime LockOSThread https golang org pkg runtime LockOSThread将一个 goroutine 绑定到一个操作系统线程 并且不允许其他 goroutine 在该线程
  • java.lang.NoSuchMethodError:com.fasterxml.jackson.databind.type。使用 apache beam Spark runner 运行 go 示例时

    我想跑grades https github com apache beam tree master sdks go examples gradesapache beam go sdk 提出的示例 在一个主服务器和两个从服务器 spark2
  • GoLang - 坚持使用 ISO-8859-1 字符集

    我正在开发一个项目 我们需要将信息保存在具有 ISO 8859 1 表的旧数据库中 因此 在向数据库写入内容之前 我需要将其从 UTF 8 转换为 ISO 8859 1 每次从数据库检索它时 我都需要将其转换回 UTF 8 我试图使用图书馆
  • 无法理解 5.6.1。注意事项:捕获迭代变量

    我正在学习 Go 但无法理解 var rmdirs func for dir range tempDirs os MkdirAll dir 0755 rmdirs append rmdirs func os RemoveAll dir NO
  • 使用 crypto/ssh 的 golang scp 文件

    我正在尝试通过 ssh 下载远程文件 以下方法在 shell 上运行良好 ssh hostname tar cz opt local folder gt folder tar gz 然而 golang 上的相同方法在输出工件大小方面存在一些
  • 共享来自单独命令/进程的属性

    我提供带有多个命令和子命令的命令行工具 我使用cobra https github com spf13 cobra命令行 我有两个单独的命令首先是前提条件e 给其他人 例如第一个命令是通过创建临时文件夹并验证某些文件来首选环境 第二个命令应
  • Golang 按位运算以及一般字节操作

    我有一些 C 代码 可以对字节执行一些按位运算 我正在尝试在 golang 中做同样的事情 但遇到了困难 C 中的示例 byte a c byte data int j c data j c byte c j c a c 0xFF c 0x
  • 我们如何在 Golang 中组合多个错误字符串?

    我是 golang 新手 我的应用程序需要在循环中返回多个错误 稍后需要组合并作为单个错误字符串返回 我无法使用字符串函数来组合错误消息 在返回之前可以使用什么方法将这些错误合并为一个错误 package main import fmt s
  • 为什么我的 SQL 占位符没有被替换(使用 Go pq)?

    根据文档 我正在这样做 var thingname string asdf var id int err database QueryRow SELECT id from things where thing thingname Scan
  • 何时在多线程中使用 易失性?

    如果有两个线程访问全局变量 那么许多教程都说使该变量成为易失性的 以防止编译器将变量缓存在寄存器中 从而无法正确更新 然而 两个线程都访问共享变量需要通过互斥体进行保护 不是吗 但在这种情况下 在线程锁定和释放互斥体之间 代码位于关键部分
  • 在使用 stop_token 等待条件变量_any 时是否需要拥有锁来请求停止?

    在等待条件变量时 更改谓词状态的线程必须拥有锁 因此在唤醒期间不会错过更新 根据文档 这是必要的 即使在使用原子变量时也是如此 不过我不确定是否request stop 已经正确处理了 那么问题是 这两个选项中哪一个是正确且符合标准的呢 j
  • 投射回更专业的界面

    我正在用 Go 编写一个游戏 在 C 中 我将所有实体类存储在 BaseEntity 类的数组中 如果一个实体需要在世界中移动 那么它将是一个从 BaseEntity 派生的 PhysEntity 但添加了方法 我尝试模仿这是 go pac
  • Gorm 总是返回带有 nil 值的结构

    我正在使用 Gorm 构建 Go Web API 作为 Amazon RDS 中 Postgresql 数据库的 ORM 问题是 Gorm 总是返回一片结构 其值全部为零 尽管数据库已经填充了数据 切片中的结构体数量是否合适取决于LIMIT
  • 如何从非英语字符串解析go中的月份

    我想将以下字符串解析为 go 中的日期 This item will be released on March 9 2014 我跟着this https stackoverflow com questions 14106541 go par
  • 使用 OpenTelemetry 统一不同服务的范围

    我刚刚开始使用 OpenTelemetry 并为此创建了两个 微 服务 Standard and GeoMap 最终用户将请求发送到Standard服务 该服务又将请求发送到GeoMap在将结果返回给最终用户之前获取信息 我使用 gRPC
  • Golang中如何获得100%的代码覆盖率? [复制]

    这个问题在这里已经有答案了 我无法获得 100 的代码覆盖率 因为我无法在 Golang 中测试 Fatals 我发现了一些问答 包括this one https stackoverflow com questions 30688554 h
  • 我应该避免在 golang 中使用单例包吗?

    现在我有一个包裹store包含以下内容 package store var db Database func Open url string error open db connection func FindAll model inter

随机推荐

  • ER_NOT_SUPPORTED_AUTH_MODE - MySQL 服务器

    连接失败Node js Server to MySQL Database 我有MariaDB 安装在 Node js 服务器 但我决定改用 SQL 数据库 我卸载了 彻底删除了 玛丽亚数据库 之后 我开始安装 社区埃德 MySQL 数据库
  • 删除具有破坏性——但并非总是如此?

    我对 Common Lisp 的破坏性 DELETE 函数有点困惑 它似乎按预期工作 除非该项目是列表中的第一项 CL USER gt defvar test list 1 2 3 TEST CL USER gt delete 1 test
  • cuda:设备函数内联和不同的.cu 文件

    两个事实 CUDA 5 0 允许您在不同的对象文件中编译 CUDA 代码 以便稍后链接 CUDA 架构 2 x 不再自动内联函数 像往常一样 在 C C 中 我实现了一个函数 device int foo in functions cu并将
  • try... except... except... :如何避免重复代码

    我想避免写作errorCount 1在不止一处 我正在寻找比更好的方法 success False try else success True finally if success storage store commit else sto
  • MATLAB 中神经网络分类的 10 倍交叉验证示例

    我正在寻找在神经网络中应用 10 倍交叉验证的示例 我需要这个问题的链接答案 MATLAB 中 10 重 SVM 分类的示例 我想对所有 3 个类别进行分类 而在示例中只考虑了两个类别 编辑 这是我为 iris 示例编写的代码 load f
  • 将结果集中的值写入文本文件(.txt 文件)

    请帮助我处理下面的代码 因为我想将结果集中的值写入 txt 文件 Code while rs next FileWriter fstream new FileWriter file BufferedWriter out new Buffer
  • 删除列标题中“.”之后的字符

    我有一个与这里提出的问题类似的问题 r 删除列名中某些字符之后的部分不过我有一点皱纹 我的列标题的格式如 ENSG00000124564 16 和 ENSG00000257509 1 但是我想删除后面的所有字符 我不能只删除最后 x 个字符
  • ie9 不尊重 img 元素比例中的 SVG

    CSS img max height 30px HTML img src foo svg 我正在寻找这个 svg 图像按比例缩放到最大高度 30 像素高 svg 的自然尺寸为 200 像素 x 200 像素 在 FF 和 Chrome 30
  • 如何获取.NET 3.5中CSIDL_COMMON_DOCUMENTS的路径?

    我正在为安装程序执行自定义操作 它必须读取存储在的文件CSIDL COMMON DOCUMENTS以确定安装目录 我希望在自定义操作中更改安装目录不会成为问题 但这是另一个问题 我看到 NET 4 添加了CommonDocuments to
  • 如何更改ggplot中图例“键”的方向?

    如何更改下面标题的键 使其处于水平位置而不更改图形的垂直线 set seed 000 m lt matrix rnorm 100 0 1 100 1 dt lt data frame m names dt lt c X library gg
  • 根据两个变量匹配数据帧行(索引)

    我本质上是试图将杂乱的数据转换成长形式以进行线性建模 我有 2 个 data frames rec 和 book book 中的每一行都需要根据行中匹配的两个变量 MRN 和 COURSE 粘贴到 rec 的几行的末尾 我已尝试以下方法及其
  • 在 Python 中从 json 数组中选取数据对象

    我有这个数据对象 我想知道如何选择名为的子对象commits or projects 我试过all commits all data commits 但 python 强迫我给它一个整数而不是字符串 想法 commits project i
  • cudaatomicAdd 示例无法产生正确的输出

    编写以下代码的目的是将 100 个元素的浮点数数组增加 1 十倍 在输出中 我期望每个元素都有 10 0f 值的 100 个元素数组 相反 我得到随机值 您能在这里指出我的错误吗 global void testAdd float a fl
  • AutoCompleteTextView 搜索部分单词而不是整个单词

    我有一个AutoCompleteTextView 并且它工作得很好 直到我在输入中添加一个空格 比如说 如果我有许多历史事件的清单 不列颠之战 1940 突出部之战 1944 插入大量战斗 拿破仑的致命进军 1812 插入许多其他历史事件
  • 数据库中电子邮件地址的最佳长度是多少?

    这是我的查询的摘录部分 反映了EMAIL ADDRESS列数据类型和属性 EMAIL ADDRESS CHARACTER VARYING 20 NOT NULL 然而 约翰 桑德斯 uses VARYING 256 这表明我不一定正确理解
  • Java:加载依赖于其他库的库

    我想在我的 java 应用程序中加载我自己的本机库 这些本机库依赖于第三方库 当我的应用程序安装在客户端计算机上时 第三方库可能存在 也可能不存在 在我的 java 应用程序中 我要求用户指定依赖库的位置 获得此信息后 我将使用它通过 JN
  • 在我网站的图像上添加 Instagram 滤镜

    我在用CSSGram在我的网站上使图像具有类似 Instagram 的滤镜 下面是向图像添加滤镜的方法
  • android中声音转换为频率[重复]

    这个问题在这里已经有答案了 可能的重复 实时音高检测 确定通过麦克风接收到的声音的音频频率 我正在开发自己的 Android 吉他调音器 在这里我将不得不使用吉他音符频率 因此 我想知道如何在android中将通过麦克风端口传来的声音转换为
  • 在静态类中使用依赖注入

    我需要在静态类中使用依赖注入 静态类中的方法需要注入依赖项的值 以下代码示例演示了我的问题 public static class XHelper public static TResponse Execute string metodo
  • 缓冲区为空后关闭“worker”go 例程

    我想要我的 goroutine 工作人员 ProcessToDo 在下面的代码中 等待所有 排队 工作处理完毕后再关闭 工作例程有一个 待办事项 通道 缓冲 通过该通道将工作发送给它 它有一个 完成 通道来告诉它开始关闭 文档称 如果满足多