渠道是做啥用的?

     2023-03-14     160

关键词:

【中文标题】渠道是做啥用的?【英文标题】:What are channels used for?渠道是做什么用的? 【发布时间】:2017-02-11 02:35:37 【问题描述】:

在查看一些 Go 代码时,我发现了以下内容:

  ch := make(chan int)

我查阅了一个在线教程,了解 Go Channels 的工作原理:

https://tour.golang.org/concurrency/2

但我觉得这个例子不清楚。

谁能给我一个简单的解释和一个使用频道的例子?

【问题讨论】:

查看这篇文章:How does golang channel works 【参考方案1】:

chan 是 Golang 中的一个频道。简而言之,您可以将其视为一个盒子,您可以在其中放置一个项目,然后从另一端拾取它。

无缓冲通道

缓冲通道

这是我为您编写的用于了解频道的小代码。现在更改 goroutine 的顺序并查看输出。每次输出可能不同。

    package main

    import (
        "fmt"
        "time"
    )

    func main() 
        messages := make(chan int)
        go func() 
            time.Sleep(time.Second * 3)
            messages <- 1
        ()
        go func() 
            time.Sleep(time.Second * 2)
            messages <- 2
        () 
        go func() 
            time.Sleep(time.Second * 1)
            messages <- 3
        ()
        go func() 
            for i := range messages 
                fmt.Println(i)
            
        ()
        go func() 
            time.Sleep(time.Second * 1)
            messages <- 4
        ()
        go func() 
            time.Sleep(time.Second * 1)
            messages <- 5
        ()
        time.Sleep(time.Second * 5)
    

为了更好地理解,请访问此博客,其中在 GUI 中描述了 go 例程和通道。

访问http://divan.github.io/posts/go_concurrency_visualize/

【讨论】:

我喜欢这些插图! 这是一个巨大的帮助!非常感谢 “顺序无关紧要” – 这不是真的。 Go 规范指出:“通道充当先进先出队列。”【参考方案2】:

我认为规范对此非常清楚。 Spec: Channel types:

通道为concurrently executing functions 提供一种机制,通过指定元素类型的sending 和receiving 值进行通信。

当您有多个并发执行的 goroutines 时,通道提供了让 goroutines 相互通信的最简单方法。

一种通信方式是通过对两个 goroutine 可见的“共享”变量,但这需要适当的锁定/同步访问。

相反,Go 偏爱频道。引用Effective Go: Share by communicating:

不要通过共享内存进行通信;相反,通过通信共享内存。

因此,例如,您可以创建一个通道(对两个 goroutine 可见),而不是将消息放入共享切片中,并且无需任何外部同步/锁定,一个 goroutine 可以通过通道发送消息(值),而另一个goroutine 可以接收它们。

在任何给定时间只有一个 goroutine 可以访问该值。设计上不会发生数据竞争。

所以事实上,任何数量的 goroutine 都可以在同一个通道上发送值,并且任何数量的 goroutine 都可以从它接收值,仍然没有任何进一步的同步。更多详情请查看相关问题:If I am using channels properly should I need to use mutexes?

频道示例

让我们看一个例子,我们启动 2 个额外的 goroutine 用于并发计算。我们将一个数字传递给第一个,它加 1,并将结果传递到第二个通道。第二个 goroutine 将接收一个数字,将其乘以 10 并将其传递到结果通道:

func AddOne(ch chan<- int, i int) 
    i++
    ch <- i


func MulBy10(ch <-chan int, resch chan<- int) 
    i := <-ch
    i *= 10
    resch <- i

这是如何调用/使用它的:

func main() 
    ch := make(chan int)
    resch := make(chan int)

    go AddOne(ch, 9)
    go MulBy10(ch, resch)

    result := <-resch
    fmt.Println("Result:", result)

通过通道进行通信还可以处理 goroutines 之间的等待。在此示例中,这意味着MulBy10() 将等待AddOne() 提供递增的数字,而main() 将在打印结果之前等待MulBy10()。按预期输出(在Go Playground 上尝试):

Result: 100

语言支持

有许多语言结构可以方便地使用频道,例如:

通道上的for ... range 循环遍历从通道接收到的值,直到通道关闭。 select 语句可用于列出多个通道操作,例如在通道上发送从通道接收,以及可以在不阻塞的情况下进行的操作将被选中(如果有多个可以继续,则随机选择;如果没有准备好,则会阻塞)。 有一种特殊形式的接收操作符,允许您检查通道是否关闭(除了接收值):v, ok := &lt;-ch 内置的len()函数告诉排队(未读)的元素数量;构建的cap() 函数返回通道缓冲区容量。

其他用途

有关更实际的示例,请参阅如何使用通道来实现worker pool。类似的用途是从producer to consumer(s) 分配值。

另一个实际例子是实现memory pool using buffered channels。

另一个实际的例子是an elegant implementation of a broker。

通道通常用于超时某些阻塞操作,利用time.After() 返回的通道,该通道在指定的延迟/持续时间后“触发”(“触发”表示将在其上发送一个值)。请参阅此示例进行演示(在Go Playground 上试用):

ch := make(chan int)

select 
case i := <-ch:
    fmt.Println("Received:", i)
case <-time.After(time.Second):
    fmt.Println("Timeout, no value received")

它可用于等待某个值的最大时间量,但如果其他 goroutine 到那时无法提供该值,我们可能会决定做其他事情。

另外一种特殊形式的通信可能只是表示某些操作已完成(实际上并未发送任何“有用”数据)。这种情况可以通过具有任何元素类型的通道来实现,例如chan int,并在其上发送任何值,例如0。但由于发送的值不包含任何信息,您可以将其声明为chan struct。或者更好的是,如果您只需要一次信号,您可以关闭可以在另一侧使用for ... range 拦截的通道,或者从它接收(因为从关闭的通道接收立即进行,产生@ 987654337@ 的元素类型)。还要知道,即使通道可以用于这种信令,也有更好的替代方案:sync.WaitGroup

进一步阅读

值得了解通道公理以避免令人惊讶的行为:How does a non initialized channel behave?

The Go Blog: Share Memory By Communicating

The Go Blog: Go Concurrency Patterns: Pipelines and cancellation

The Go Blog: Advanced Go Concurrency Patterns

Ardan labs: The Nature Of Channels In Go

【讨论】:

我喜欢这个答案,尤其是关于使用 time.After(time.Second) 的部分。我不知道可以这样做。【参考方案3】:

为了更好地理解 Go 中通道的概念,您可以先了解 Go 例程,然后阅读下面的链接,该链接清楚地解释了 golang 中的通道概念。

https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb

请参阅此链接以借助示例详细了解频道。

【讨论】:

欢迎来到 ***! *** 旨在积累好的问题和好的答案。请编辑您的帖子并修复链接。您可以看到 2 人已经为这个问题提供了很好的答案。为什么不做通俗易懂的解释,而不是让人们上网呢?如果您认为您可以提供更好的答案(与现有的 2 个答案相比),请扩展您的答案。【参考方案4】:

这个概念与 Unix/Linux 从一开始就存在的东西非常相似:管道。

这些是语言内置的可靠的进程间/线程间通信工具。很方便。

【讨论】:

sigaddset 是做啥用的?

】sigaddset是做啥用的?【英文标题】:Whatissigaddsetusedfor?sigaddset是做什么用的?【发布时间】:2014-12-0111:37:41【问题描述】:我有这段代码,我使用sigaddset和sigaction。但是,如果我评论segaddset结果是一样的structsigactionact;act.sa_handl... 查看详情

maven.multiModuleProjectDirectory 是做啥用的?

】maven.multiModuleProjectDirectory是做啥用的?【英文标题】:Whatismaven.multiModuleProjectDirectoryusedfor?maven.multiModuleProjectDirectory是做什么用的?【发布时间】:2015-06-2823:19:04【问题描述】:我在SO和Maven邮件列表上看到了很多关于设置env参... 查看详情

cursor.setNotificationUri() 是做啥用的?

】cursor.setNotificationUri()是做啥用的?【英文标题】:Whatiscursor.setNotificationUri()usedfor?cursor.setNotificationUri()是做什么用的?【发布时间】:2014-03-0415:02:29【问题描述】:我研究了如何使用ContentProviders和来自thistutorial的加载器我是怎... 查看详情

itertools.groupby() 是做啥用的?

】itertools.groupby()是做啥用的?【英文标题】:Whatisitertools.groupby()usedfor?itertools.groupby()是做什么用的?【发布时间】:2017-05-1515:43:37【问题描述】:在阅读python文档时,我遇到了itertools.groupby()功能。这不是很简单,所以我决定在... 查看详情

MAKEWORD 是做啥用的?

】MAKEWORD是做啥用的?【英文标题】:WhatisMAKEWORDusedfor?MAKEWORD是做什么用的?【发布时间】:2014-06-1002:14:20【问题描述】:我在一段教学代码中遇到了这个宏MAKEWORD(2,2)。我在MSDN中读到它“通过连接指定的值来创建一个WORD值。”... 查看详情

Laravel 中的 `HtmlString` 是做啥用的?

】Laravel中的`HtmlString`是做啥用的?【英文标题】:Whatis`HtmlString`usedforinLaravel?Laravel中的`HtmlString`是做什么用的?【发布时间】:2017-07-0806:01:45【问题描述】:本课程:HtmlStringhtml=$html;/***获取HTML字符串。**@return字符串*/公共函数t... 查看详情

EasyMock.replay() 是做啥用的?

】EasyMock.replay()是做啥用的?【英文标题】:WhatisEasyMock.replay()usedfor?EasyMock.replay()是做什么用的?【发布时间】:2011-08-2415:14:28【问题描述】:我是单元测试和Junit的新手。我知道Junit的基础知识。我刚开始学习EasyMock框架。我无... 查看详情

SetPixelFormat() 中的 PIXELFORMATDESCRIPTOR 参数是做啥用的?

】SetPixelFormat()中的PIXELFORMATDESCRIPTOR参数是做啥用的?【英文标题】:WhatisthePIXELFORMATDESCRIPTORparameterinSetPixelFormat()usedfor?SetPixelFormat()中的PIXELFORMATDESCRIPTOR参数是做什么用的?【发布时间】:2010-03-2918:51:16【问题描述】:通常在设... 查看详情

Iterable 接口是做啥用的?

】Iterable接口是做啥用的?【英文标题】:WhatistheIterableinterfaceusedfor?Iterable接口是做什么用的?【发布时间】:2010-11-0617:52:36【问题描述】:我是初学者,无法理解Iterable界面的真实效果。【问题讨论】:【参考方案1】:除了Jere... 查看详情

predicateWithBlock: 中块的 bindings 参数是做啥用的?

】predicateWithBlock:中块的bindings参数是做啥用的?【英文标题】:WhatisthebindingsparameterfortheblockinpredicateWithBlock:usedfor?predicateWithBlock:中块的bindings参数是做什么用的?【发布时间】:2011-09-1914:10:01【问题描述】:+[NSPredicatepredicateWithB... 查看详情

app.config 是做啥用的?

】app.config是做啥用的?【英文标题】:Whatisapp.configfor?app.config是做什么用的?【发布时间】:2010-11-2817:44:52【问题描述】:Settings.settings生成Settings.Designer.cs,它可能会生成app.config,然后将其作为Foo.exe.config复制到输出目录。当... 查看详情

UITextInput 的 Tokenizer,它是做啥用的?

】UITextInput的Tokenizer,它是做啥用的?【英文标题】:TokenizerofUITextInput,whatisitusedfor?UITextInput的Tokenizer,它是做什么用的?【发布时间】:2013-05-0210:17:12【问题描述】:我正在实现一个自定义文本输入视图,它采用UITextInput协议,... 查看详情

namedtuple 的第一个参数是做啥用的?

】namedtuple的第一个参数是做啥用的?【英文标题】:What\'sthefirstargumentofnamedtupleusedfor?namedtuple的第一个参数是做什么用的?【发布时间】:2015-08-1202:46:34【问题描述】:我们像这样使用namedtuple:>>>fromcollectionsimportnamedtuple&... 查看详情

eq是做啥用的,它和压缩一样吗.如果不一样那压缩是做啥用的~

EQ是频率均衡器,它能够允许用户主动地对声音的各频段进行增益或衰减的处理。压缩是是对电信号的处理装置,它会将过大的电压减弱,过小的电压增强,体现在声音上就是能够让音箱中放出的声音稳定在一个设定的范围,尤... 查看详情

用户定义的操作“类型”是做啥用的?

】用户定义的操作“类型”是做啥用的?【英文标题】:Whatistheuserdefinedaction"type"for?用户定义的操作“类型”是做什么用的?【发布时间】:2016-08-0801:43:29【问题描述】:这里的“类型”列有什么作用?【问题讨论】:... 查看详情

测试和设置是做啥用的?

】测试和设置是做啥用的?【英文标题】:WhatisTest-and-Setusedfor?测试和设置是做什么用的?【发布时间】:2008-09-2313:22:00【问题描述】:在阅读了Test-and-SetWikipediaentry之后,我仍然想知道“Test-and-Set的用途是什么?”我知道您可... 查看详情

cacert.pem 到底是做啥用的?

】cacert.pem到底是做啥用的?【英文标题】:Whatexactlyiscacert.pemfor?cacert.pem到底是做什么用的?【发布时间】:2013-02-0522:14:39【问题描述】:在我的PayPalPro支付页面中,我使用cURL函数curl_setopt_array()和以下选项:cUInCURLOPT_CAINFO=&gt... 查看详情

pyproject.toml 文件是做啥用的?

】pyproject.toml文件是做啥用的?【英文标题】:Whatispyproject.tomlfilefor?pyproject.toml文件是做什么用的?【发布时间】:2020-11-0900:26:03【问题描述】:背景我正准备尝试从GitHub下载的Python包,发现它没有setup.py,所以我无法安装它pipin... 查看详情