channel的用法基础

news/2025/2/21 17:00:46/文章来源:https://www.cnblogs.com/regit/p/18729565

一. channel的简单用法

func worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d processing job %d\n", id, job)time.Sleep(time.Second)results <- job * 2}
}

这段代码定义了一个名为 worker 的函数,它模拟了一个工作线程(或称为“工人”),用于处理输入的作业(jobs),并将处理结果发送到结果通道(results)。以下是对代码的详细解释:

1. 函数名

func worker(id int, jobs <-chan int, results chan<- int)
  • id int:表示当前工作线程的编号,用于标识不同的工作线程。
  • jobs <-chan int:一个只读通道(<-chan),用于接收作业。通道中的数据类型是 int,表示每个作业是一个整数。
  • results chan<- int:一个只写通道(chan<-),用于发送处理结果。通道中的数据类型也是 int

2. 函数体

for job := range jobs {fmt.Printf("Worker %d processing job %d\n", id, job)time.Sleep(time.Second)results <- job * 2
}
  1. for job := range jobs
    • 这是一个无限循环,用于从 jobs 通道中接收作业。
    • range 关键字用于迭代通道中的值,直到通道关闭。
    • 每次循环中,job 变量会接收通道中的一个整数值。
  2. fmt.Printf("Worker %d processing job %d\n", id, job)
    • 使用 fmt.Printf 打印日志信息,表示当前工作线程正在处理哪个作业。
    • id 是工作线程的编号,job 是当前正在处理的作业编号。
  3. time.Sleep(time.Second)
    • 为了模拟工作线程处理作业需要花费时间,这里使用 time.Sleep 暂停 1 秒。
    • 在实际应用中,这里可以替换为实际的处理逻辑。
  4. results <- job \* 2
    • 将处理结果发送到 results 通道。
    • 在这个例子中,处理逻辑是将输入的作业值乘以 2。

3. 总结

这段代码的核心功能是:

  1. jobs 通道接收作业。
  2. 模拟处理作业(这里通过暂停 1 秒来模拟)。
  3. 将处理结果(输入值乘以 2)发送到 results 通道。

4. 使用场景

这段代码通常用于并发编程中的工作池模式(Worker Pool)。多个工作线程(worker)可以同时从 jobs 通道中获取作业,并将结果发送到 results 通道。通过这种方式,可以高效地处理大量并发任务。

例如,可以在主程序中启动多个 worker,并将作业分配到 jobs 通道中:

package mainimport ("fmt""time"
)func worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d processing job %d\n", id, job)time.Sleep(time.Second)results <- job * 2}
}func main() {jobs := make(chan int, 10)results := make(chan int, 10)// 启动 3 个工作线程for i := 1; i <= 3; i++ {go worker(i, jobs, results)}// 发送作业for i := 1; i <= 5; i++ {jobs <- i}close(jobs) // 关闭通道,通知工作线程停止// 接收结果for j := 1; j <= 5; j++ {fmt.Printf("Result: %d\n", <-results)}
}

在这个例子中:

  • 主程序启动了 3 个工作线程。
  • 每个工作线程从 jobs 通道中获取作业,并将结果发送到 results 通道。
  • 主程序从 results 通道中接收处理结果并打印。

二. 只读通道和只写通道的解释

在 Go 中,通道(channel)可以被定义为只读通道<-chan)或只写通道chan<-),这取决于通道的使用方式。这种定义方式可以增加代码的可读性和安全性,避免错误地对通道进行不合适的操作。

1. jobs <-chan intresults chan<- int 的区别

  • jobs <-chan int:这是一个只读通道。它只能用于从通道中读取数据,而不能向其中写入数据。它的语法是 <-chan,表示数据流向是从通道流向外部。

    go复制

    for job := range jobs {// 可以从 jobs 中读取数据,但不能写入
    }
    
  • results chan<- int:这是一个只写通道。它只能用于向通道中写入数据,而不能从其中读取数据。它的语法是 chan<-,表示数据流向是从外部流向通道。

    go复制

    results <- job * 2
    // 可以向 results 中写入数据,但不能从中读取
    

2. 为什么说 results 是只写通道?

虽然在代码中可以看到 results 被用作通道,但它的定义是 chan<- int,表示它只能用于写入数据。这种定义方式是为了限制通道的使用范围,确保在函数内部不会意外读取通道中的数据。

3. 为什么 fmt.Printf("Result: %d\n", <-results) 可以读取数据?

在主程序中,results 是一个普通的通道(chan int),而不是只写通道。主程序中定义的通道可以同时用于读写操作。例如:

go复制

results := make(chan int, 10)

在这个定义中,results 是一个普通的通道,可以在主程序中读取或写入数据。

然而,在 worker 函数中,results 被定义为只写通道(chan<- int),这是为了限制函数内部的操作,确保它只能向通道中发送数据,而不能读取通道中的数据。

4. 总结

  • 只读通道(<-chan:只能从通道中读取数据,不能写入。
  • 只写通道(chan<-:只能向通道中写入数据,不能读取。
  • 普通通道(chan:可以同时用于读写操作。

在函数参数中使用只读或只写通道可以增加代码的可读性和安全性,避免在函数内部对通道进行不合适的操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/887662.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DeepSeek 满血版在 VScode 和 IDEA 中怎么用?手把手教程来了

DeepSeek 满血版在 IDEA 中怎么用?手把手教程来了作者:沉默王二近期有几个热点事件,不知道大家关注到没有?第一个标志事件,一向挑剔的苹果宣布和阿里合作,一起为国行版 iPhone 提供 AI 技术服务。 第二个标志事件,DeepSeek R1 蒸馏了 6 个模型开源给社区,其中有 4 个来…

redission-delay-queue使用及原理

1.引入jar包<dependency><groupId>xxxx.delay</groupId><artifactId>redisson-delayed-queue</artifactId><version>1.0.0-SNAPSHOT</version> </dependency>2.客户端代码开发2.1:新增实现BaseTask的bean 参数由业务自行决定…

利用网页爬虫从专业产品论坛提取评论的完整指南

了解如何通过网页爬虫从专业产品论坛提取评论,以获取可操作的洞见、改进策略,并节省时间。利用网页爬虫从专业产品论坛提取评论已经成为企业的游戏规则改变者。它使您能够从多个平台收集客户反馈(https://dataforest.ai/blog/top-web-scraping-use-cases),实时监控情绪,并自…

树的重心(树形dp)

我最开始将n减了1,应为边长有n-1条,但是这会导致计算时出现错误,因为其他地方会用到n#include<iostream> #include<vector> using namespace std; const int N=1e5+5; vector<int>v[N]; int f[N]; int vis[N]; int ans=1e5; int n; int dfs(int x){vis[x]…

仓库管理到底该怎么管?记住这五常六准原则!

仓库管理到底该怎么管? 要是你觉得仓库只是个“堆货的地方”,那可就大错特错了! 想象一下,货物乱成一团,找东西时费劲,出库慢,结果错发了货,那可真的是“大麻烦”啊。 客户打电话来投诉,老板又来催货,这种情况谁遇到谁头疼。 但其实,仓库管理不复杂,只要掌握了一些…

让窗口显示在所有虚拟桌面上

功能如图 C#代码实现如下public partial class MainWindow : Window {public MainWindow(){InitializeComponent();ShowInTaskbar = false;this.Loaded += MainWindow_Loaded;}private void MainWindow_Loaded(object sender, RoutedEventArgs e){IntPtr a = new System.Window…

[Vite] 性能优化

关于HTTP: https://www.cnblogs.com/Answer1215/p/18729206 DNS 打包方式:所有代码(包括 lodash-es、element-ui 等)被打包到一起,部署时只需请求一个或几个大文件。 优点是简单,不需要额外的网络请求;缺点是文件体积大,首次加载延迟较高,而且用户如果之前访问过其他…

python 并发场景梳理

一、多进程(Multiprocessing) 1、使用场景 适合CPU密集型任务,因为每个进程运行在独立的Python解释器中,不受全局解释器锁(GIL)的影响。 2、代码from multiprocessing import Process import timedef task():print("Task is running")time.sleep(10)processes …

Pic2Word

目录概Pic2Word代码Saito K., Sohn K., Zhang X., Li C., Lee C., Saenko K., and Pfister T. Pic2Word: Mapping pictures to words for zero-shot composed image retrieval. CVPR, 2023.概 本文关注的是 Composed Image Retrieval (CIR) 任务: 给定一个 reference (query) i…

SciTech-EECS-BigDataAIML-NN(神经网络): 常用的18种Activation(激活函数)

SciTech-EECS-BigDataAIML-NN(神经网络): 常用的18种Activation(激活函数) 一:简介 二:为什么要用激活函数 三:激活函数的分类 四:常见的几种激活函数 4.1.Sigmoid函数 4.2.Tanh函数 4.3.ReLU函数 4.4.Leaky Relu函数 4.5.PRelu函数 4.6.ELU函数 4.7.SELU函数 4.8.Swish函数…

用了CRM后,业绩不升反滑?问题可能出在这6个地方!

用了CRM系统后,我的公司——客户跟丢了 销售效率下降了 业绩一落千丈哈哈,比我惨的还有谁?! 不过我潜心研究了一阵,终于把这个CRM系统给弄懂了! 今天就跟大家聊一聊,为什么用了CRM系统后不仅没能提升业绩,反而拖了后腿,这是踩了哪些坑?以及该怎么调整才能真正发挥CRM…

功率MOS管的参数说明

图解功率MOS管的每一个参数!最大额定参数 最大额定参数,所有数值取得条件(Ta=25℃)VDSS 最大漏-源电压 在栅源短接,漏-源额定电压(VDSS)是指漏-源未发生雪崩击穿前所能施加的最大电压。根据温度的不同,实际雪崩击穿电压可能低于额定VDSS。关于V(BR)DSS的详细描述请参见静电…