当涉及多个渠道时,select 如何工作?

2024-05-12

我发现在多个非缓冲通道上使用 select 时,例如

select {
case <- chana:
case <- chanb:
}

即使两个通道都有数据,但在处理此选择时, case chana 和 case chanb 的跟注不平衡。

package main

import (
    "fmt"
    _ "net/http/pprof"
    "sync"
    "time"
)

func main() {
    chana := make(chan int)
    chanb := make(chan int)

    go func() {
        for i := 0; i < 1000; i++ {
            chana <- 100 * i
        }
    }()

    go func() {
        for i := 0; i < 1000; i++ {
            chanb <- i
        }
    }()

    time.Sleep(time.Microsecond * 300)

    acount := 0
    bcount := 0
    wg := sync.WaitGroup{}
    wg.Add(1)
    go func() {
        for {
            select {
            case <-chana:
                acount++
            case <-chanb:
                bcount++
            }
            if acount == 1000 || bcount == 1000 {
                fmt.Println("finish one acount, bcount", acount, bcount)
                break
            }
        }
        wg.Done()
    }()

    wg.Wait()
}

运行这个demo,当其中一个chana,chanb完成读/写时,另一个可能还剩下999-1。

有什么方法可以保证平衡吗?

找到相关主题
golang 通道选择语句 https://stackoverflow.com/questions/19865194/golang-channels-select-statement


The Go select https://golang.org/ref/spec#Select_statements声明不偏向任何(现成的)案例。引用规范:

如果一个或多个通信可以继续进行,则通过均匀伪随机选择。否则,如果存在默认情况,则选择该情况。如果不存在默认情况,则“select”语句将阻塞,直到至少其中一个通信可以继续进行。

如果可以进行多个通信,则随机选择一个。这不是完美的随机分布,规范也不能保证这一点,但它是随机的。

你所体验到的是 Go Playground 的结果GOMAXPROCS=1 (你可以在这里验证 https://play.golang.org/p/GIIyXQb643)并且 goroutine 调度程序不是抢占式的。这意味着默认情况下 goroutine 不是并行执行的。如果遇到阻塞操作(例如,从网络读取,或尝试在阻塞的通道上接收或发送),则将 goroutine 置于停放状态,而另一个准备运行的 goroutine 将继续运行。

而且由于您的代码中没有阻塞操作,因此 goroutine 可能不会被放入公园,并且可能只有您的“生产者”goroutines 之一会运行,而另一个可能不会被调度(永远)。

在我的本地计算机上运行您的代码GOMAXPROCS=4,我得到了非常“现实”的结果。运行几次,输出:

finish one acount, bcount 1000 901
finish one acount, bcount 1000 335
finish one acount, bcount 1000 872
finish one acount, bcount 427 1000

如果您需要优先考虑单个案例,请查看以下答案:强制 go select 语句的优先级 https://stackoverflow.com/questions/46200343/force-priority-of-go-select-statement/46202533#46202533

默认行为select不保证同等优先级,但平均而言会接近它。如果您需要保证同等优先级,那么您不应该使用select,但是您可以从 2 个通道执行一系列 2 个非阻塞接收,如下所示:

for {
    select {
    case <-chana:
        acount++
    default:
    }
    select {
    case <-chanb:
        bcount++
    default:
    }
    if acount == 1000 || bcount == 1000 {
        fmt.Println("finish one acount, bcount", acount, bcount)
        break
    }
}

如果两个通道都提供值,则上述 2 个非阻塞接收将以相同的速度(具有相同的优先级)耗尽 2 个通道,如果一个通道没有提供值,则另一个通道将不断接收而不会出现延迟或阻塞。

关于这一点需要注意的一件事是,如果none的通道提供任何要接收的值,这基本上将是一个“繁忙”循环,因此消耗计算能力。为了避免这种情况,我们可能会检测到没有任何通道准备就绪,并且then use a select语句与两个接收,然后将阻塞,直到其中之一准备好接收,不浪费任何 CPU 资源:

for {
    received := 0
    select {
    case <-chana:
        acount++
        received++
    default:
    }
    select {
    case <-chanb:
        bcount++
        received++
    default:
    }

    if received == 0 {
        select {
        case <-chana:
            acount++
        case <-chanb:
            bcount++
        }
    }

    if acount == 1000 || bcount == 1000 {
        fmt.Println("finish one acount, bcount", acount, bcount)
        break
    }
}

有关 goroutine 调度的更多详细信息,请参阅以下问题:

Go运行时使用的线程数 https://stackoverflow.com/questions/39245660/number-of-threads-used-by-go-runtime/39246575#39246575

Goroutines 8kb 和 Windows 操作系统线程 1 mb https://stackoverflow.com/questions/30073441/goroutines-8kb-and-windows-os-thread-1-mb/30074921#30074921

为什么golang写文件时很多goroutine被阻塞却没有创建很多线程? https://stackoverflow.com/questions/28186361/why-does-it-not-create-many-threads-when-many-goroutines-are-blocked-in-writing/28186656#28186656

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

当涉及多个渠道时,select 如何工作? 的相关文章

  • 将中间件与 Golang Gorilla mux 子路由器结合使用

    如何将中间件应用到 Go 中大猩猩工具包 http www gorillatoolkit org 多路复用器子路由器 我有以下代码 router mux NewRouter StrictSlash true apiRouter router
  • 如何拥有在标准输出上更新的就地字符串

    我想输出到标准输出并让输出 覆盖 以前的输出 例如 如果我输出On 1 10 我想要下一个输出On 2 10覆盖On 1 10 我怎样才能做到这一点 stdout是一个流 io Writer 您无法修改已写入其中的内容 什么can更改的是该
  • 为什么 DER ASN.1 大整数的解组在 Golang 中仅限于 SEQUENCE?

    我希望能够使用encoding asn1 包从 DER 文件中解组一个大整数 但它看起来只适用于整数序列 例如 这不起作用 这很奇怪 因为 Big Int 的编组效果很好 https play golang org p Wkj0jAA6bp
  • 如何对结构切片而不是切片结构进行范围调整

    稍微玩了一下 Go HTML 模板后 我发现的所有循环模板中对象的示例都是将切片结构传递给模板 有点像这个示例 type UserList struct Id int Name string var templates template M
  • 云存储 API 的错误导入“系统调用”

    我正在按照以下说明进行操作https cloud google com appengine docs go googlecloudstorageclient download开始将一些代码从现已弃用的文件 API 迁移到新的 Cloud S
  • 如何使用 go1.6.2 构建 linux 32 位

    有没有任何组合GOARCH and GOOS我可以设置哪些值来构建 ELF 32 位二进制文 件 GOOS linux and GOARCH 386 更多示例 架构 32 bit gt GOARCH 386 64 bit gt GOARCH
  • 查看oracle中重复行的所有数据

    我有一个有 6 列的表 id name type id code lat long 前三个是必需的 ID是私钥 按序列自动插入 我有一些重复的行 正如两者所定义的name and type id是平等的 但我想查看受骗者的所有数据 我可以很
  • MySQL - 从另一个表插入与常量合并的数据

    我有一个包含一些数据的临时表 products temp 并且我有另一个需要将数据插入其中的表 产品 我需要在新记录上手动设置一些常量 例如vendor id 1等 是否可以在一次请求中插入临时表数据和常量 临时产品 product nam
  • 结构体到磁盘的高效 Go 序列化

    我的任务是将 C 代码替换为 Go 而且我对 Go API 还很陌生 我正在使用 gob 将数百个键 值条目编码到磁盘页面 但 gob 编码有太多不需要的膨胀 package main import bytes encoding gob f
  • jQuery UI 1.8.17 和 selectmenu

    这个问题的答案可能会让我 doh 时刻 但是我在哪里可以找到一个可与较晚 ish jquery ui 版本一起使用的有效 selectmenu 插件 我从所有这些地方尝试过 但似乎都不起作用 http www filamentgroup c
  • 使用生成的 Golang DLL 返回字符串或 *C.Char

    我一直在努力追随z505 goDLL https github com z505 goDLL回购并遇到了一个大问题 该方法无法返回字符串 我无法读取结果的输出变量 这是我到目前为止使用的代码 Go 完整代码https play golang
  • pq:函数unnest(未知)不是唯一的

    以下代码工作正常 但我想将 array a b c d e 定义为变量 rows err db Query select colname from SELECT date unnest array a b c d e AS colname
  • 我使用go语言打印到POS打印机,但打印出的中文字符很糟糕。 (英语没问题)

    我在用着this https github com alexbrainman printer去打包 一切都很好 但汉字打印得很差 我不擅长这种低级 硬件 编码的事情 所以有人提示我如何纠正我的代码 更新代码 func main testWi
  • Python pandas 按日期列表选择行

    如何通过日期列表选择数据框的多行 dates pd date range 20130101 periods 6 df pd DataFrame np random randn 6 4 index dates columns list ABC
  • 为什么 Go 中不允许在包级别声明短变量?

    这是允许的 package main var a 3 但这不是 package main a 3 为什么不 为什么不能将函数外部的短变量声明视为没有类型的常规声明 只是为了简化解析 根据伊恩 兰斯 泰勒的说法这个线程 https group
  • 在 OSX 上交叉编译 Go?

    我正在尝试在 OSX 上交叉编译 go 应用程序以构建适用于 Windows 和 Linux 的二进制文件 我已经阅读了网上能找到的所有内容 我发现的最接近的例子已经发布在 除了疯狂邮件列表上许多未完成的讨论之外 http solovyov
  • 子查询在多项选择时返回超过 1 个值的 SQL 错误

    我想要一个临时表 它将使用 select 语句插入值 但每次我运行查询时 总是出现错误 子查询返回超过 1 个值 当查询跟随 gt 或子查询用作表达式时 不允许这样做 该语句已终止 0 行受影响 这很奇怪 因为代码中似乎没有错误 但如果有的
  • 在 Go 中解析 RFC-3339 / ISO-8601 日期时间字符串

    我尝试解析日期字符串 2014 09 12T11 45 26 371Z 在围棋中 该时间格式定义为 RFC 3339 日期时间 https datatracker ietf org doc html rfc3339 section 5 6
  • 限制 FormFile 中的文件大小

    我让用户使用 FormFile 上传文件 我应该在什么时候检查文件大小是否太大 当我做 file header fileErr r FormFile file 文件对象已经创建 那么我是否已经产生了读取整个文件的成本 https golan
  • 在 Go 中,如何将函数的 stdout 捕获到字符串中?

    例如 在 Python 中 我可以执行以下操作 realout sys stdout sys stdout StringIO StringIO some function prints to stdout get captured in t

随机推荐

  • 如何多线程从列表中读取字典并输入数据库

    我正在尝试对以下代码进行多线程处理 但似乎无法使其正常工作 以下代码 其中我删除了大部分代码只是为了说明目的 目前运行顺利 但速度很慢 对于 3600 条推文的列表大约需要 5 分钟 import dataset import dateti
  • Heroku 上的 Python 入门 - 未找到 pg_config 可执行文件

    我一直在关注文档 直到安装requirements txt 文件 尝试安装第 6 行 psycopg2 2 5 3 时总是失败 这是消息 Downloading unpacking psycopg2 2 5 3 from r require
  • 了解 U-Boot 内存占用

    我不明白加载 U Boot 时 RAM 中发生了什么 我正在开发 Xilinx Zynq ZC702 评估套件 并尝试使用 U Boot 在其上加载 Linux 内核 于是我使用Xilinx工具Vivado和SDK生成了一个BOOT bin
  • 在 System.Windows.Forms.RichTextBox 中禁用 VScrollbar 的绘制

    我有一个继承自 RichTextBox 的自定义控件 该控件能够 禁用 富文本编辑 我通过在 TextChanged 事件期间将 Rtf 属性设置为 text 属性来实现此目的 这就是我的代码的样子 private bool lockTex
  • 将文件从一个文件夹移动到 s3 中的另一个文件夹

    首先 我尝试将文件复制到其他文件夹中 但无法删除它 仅当文件复制到目标文件夹时 如何才能删除该文件 const s3Params Bucket bucket CopySource bucket objectkey Key processed
  • Python行、列、矩阵麻烦

    我正在编写一个带有给定的Python程序 matrix A B C D E F G H I 我正在尝试编写代码 以便可以定义每个值的坐标 这样如果我的命令是 get cooperative 矩阵中的任何值 它将打印出矩阵中的行和列 我很难定
  • Jetpack 在可滚动列中组合 LazyColumn

    这是我的情况 我必须在我的应用程序中显示从 API 收到的记录的详细信息 在此视图中 我可能需要也可能不需要基于字段显示来自另一个视图模型的一些数据 这是我的代码 OptIn ExperimentalMaterial3Api class C
  • if 不是 localhost 语句 htaccess

    我目前强迫访问者通过 https 访问我的所有网站 主要是 Wordpress 我使用以下代码 RewriteEngine On RewriteCond HTTPS on RewriteRule https SERVER NAME REQU
  • angularjs - 当 $interval 触发时 ng-show 不会更新类

    尝试使用 Angular 中的 interval 来使用 ng show 更改列表中当前可见的项目 检查 html 我注意到角度将 ng show 从 true false 更改 但它并没有删除 ng hide 类 html 很简单 h1
  • 动态添加 href 到链接

    我有一系列水平 div 框 我需要添加相关的 href 以使用锚链接链接到下一个 由于它们是动态生成的 我需要使用 JavaScript 添加 href 期望的效果将是 div a class next video href post2 N
  • 要发布哪些运行时库?

    我使用 Visual Studio 2008 进行 C C 工作 我相信我并不关心我的代码使用了哪些运行时库 因为我有开发人员设置 但是 当交付可执行文件时 所使用的运行时库也需要一起交付 我对吗 如果是 我如何确定实际使用了哪些共享库 或
  • Haskell scala 互操作性

    我是 Scala 初学者 来自面向对象范式 在了解 Scala 的函数式编程部分时 我被引导到 Haskell 纯函数式编程语言 探索 SO 问题答案 我发现 Java Haskell 具有互操作性 我很想知道 Scala Haskell
  • CakePHP 3.X 中的自定义 404 页面

    我想为生产环境中出现的所有错误创建一个自定义 404 页面 例如 如果我收到缺少控制器或视图错误 那么它将重定向到http example com 404 html 另外在某些情况下我会故意重定向它http example com 404
  • 如何使用 setuptools Windows 安装程序在开始菜单中创建快捷方式

    我想为我的 Python Windows 安装程序包创建开始菜单或桌面快捷方式 我正在尝试遵循https docs python org 3 4 distutils builtdist html the post 安装脚本 https do
  • .net Mef 与企业库 5.0

    我想将 mef 与 Enterprise Library 5 0 的日志记录和异常块一起使用 我正在做的是定义 MEF 在目录中查找的插件 然后它为我导入它 不过 我也在插件中使用日志记录和异常处理 我希望能够通过 mef 插入 LogWr
  • 非文本区域元素的选择开始

    element 0 selectionStart似乎只适用于文本区域 非文本区域有替代方案吗 我试图将字符串包装在标签中的 DOM 元素中 粗体 斜体 另外 如何解开包装纸 这是一个棘手的领域 你需要选择 https developer m
  • 异步迭代器 Task>

    我正在尝试实现一个返回迭代器的异步函数 这个想法如下 private async Task
  • CSV、Python:正确使用 DictWriter(ValueError:dict 包含不在字段名中的字段)

    我在掌握 csv 模块 Python 2 7 中的 DictWriter 时遇到困难 我有这个 哦 我正在使用 unicodecsv 库 因为我读到存在问题 f object instance return a dictionary key
  • 在电子打印中构建的角度应用程序显示空白窗口

    我开发了一个角度应用程序 然后在电子中构建该应用程序 该应用程序工作正常 但是当我单击按钮打印特定 div 时 它会打开一个电子的空白窗口 我用ngx print图书馆 它在角度服务方面效果很好 但在电子构建方面遇到了问题
  • 当涉及多个渠道时,select 如何工作?

    我发现在多个非缓冲通道上使用 select 时 例如 select case lt chana case lt chanb 即使两个通道都有数据 但在处理此选择时 case chana 和 case chanb 的跟注不平衡 package