GO语言网络编程(并发编程)Channel
GO语言网络编程(并发编程)Channel
1、Channel
1.1.1 Channel
单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。
虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。
Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信。
如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。
Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。
1.1.2 channel类型
channel是一种类型,一种引用类型。声明通道类型的格式如下:
var 变量 chan 元素类型
举几个例子:
var ch1 chan int // 声明一个传递整型的通道var ch2 chan bool // 声明一个传递布尔型的通道var ch3 chan []int // 声明一个传递int切片的通道
1.1.3. 创建channel
通道是引用类型,通道类型的空值是nil。
var ch chan int
fmt.Println(ch) // <nil>
声明的通道后需要使用make函数初始化之后才能使用。
创建channel的格式如下:
make(chan 元素类型, [缓冲大小])
channel的缓冲大小是可选的。
举几个例子:
ch4 := make(chan int)
ch5 := make(chan bool)
ch6 := make(chan []int)
1.1.4 channel操作
通道有发送(send)、接收(receive)和关闭(close)三种操作。
发送和接收都使用<-符号。
现在我们先使用以下语句定义一个通道:
ch := make(chan int)
发送
将一个值发送到通道中。
ch <- 10 // 把10发送到ch中
接收
从一个通道中接收值。
x := <- ch // 从ch中接收值并赋值给变量x
<-ch // 从ch中接收值,忽略结果
关闭
我们通过调用内置的close函数来关闭通道。
close(ch)
关于关闭通道需要注意的事情是,只有在通知接收方goroutine所有的数据都发送完毕的时候才需要关闭通道。通道是可以被垃圾回收机制回收的,它和关闭文件是不一样的,在结束操作之后关闭文件是必须要做的,但关闭通道不是必须的。
关闭后的通道有以下特点:
1.对一个关闭的通道再发送值就会导致panic。2.对一个关闭的通道进行接收会一直获取值直到通道为空。3.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。4.关闭一个已经关闭的通道会导致panic。
1.1.5 无缓冲的通道
无缓冲的通道又称为阻塞的通道。我们来看一下下面的代码:
func main() {ch := make(chan int)ch <- 10fmt.Println("发送成功")
}
上面这段代码能够通过编译,但是执行的时候会出现以下错误:
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:
main.main().../src/github.com/pprof/studygo/day06/channel02/main.go:8 +0x54
为什么会出现deadlock错误呢?
因为我们使用ch := make(chan int)创建的是无缓冲的通道,无缓冲的通道只有在有人接收值的时候才能发送值。就像你住的小区没有快递柜和代收点,快递员给你打电话必须要把这个物品送到你的手中,简单来说就是无缓冲的通道必须有接收才能发送。
上面的代码会阻塞在ch <- 10这一行代码形成死锁,那如何解决这个问题呢?
一种方法是启用一个goroutine去接收值,例如:
func recv(c chan int) {ret := <-cfmt.Println("接收成功", ret)
}
func main() {ch := make(chan int)go recv(ch) // 启用goroutine从通道接收值ch <- 10fmt.Println("发送成功")
}
无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作,这时值才能发送成功,两个goroutine将继续执行。相反,如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值。
使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
1.1.6 有缓冲的通道
解决上面问题的方法还有一种就是使用有缓冲区的通道。
我们可以在使用make函数初始化通道的时候为其指定通道的容量,例如:
func main() {ch := make(chan int, 1) // 创建一个容量为1的有缓冲区通道ch <- 10fmt.Println("发送成功")
}
只要通道的容量大于零,那么该通道就是有缓冲的通道,通道的容量表示通道中能存放元素的数量。就像你小区的快递柜只有那么个多格子,格子满了就装不下了,就阻塞了,等到别人取走一个快递员就能往里面放一个。
我们可以使用内置的len函数获取通道内元素的数量,使用cap函数获取通道的容量,虽然我们很少会这么做。
1.1.7
可以通过内置的close()函数关闭channel(如果你的管道不往里存值或者取值的时候一定记得关闭管道)
package mainimport "fmt"func main() {c := make(chan int)go func() {for i := 0; i < 5; i++ {c <- i}close(c)}()for {if data, ok := <-c; ok {fmt.Println(data)} else {break}}fmt.Println("main结束")
}
1.1.8 如何优雅的从通道循环取值
当通过通道发送有限的数据时,我们可以通过close函数关闭通道来告知从该通道接收值的goroutine停止等待。当通道被关闭时,往该通道发送值会引发panic,从该通道里接收的值一直都是类型零值。那如何判断一个通道是否被关闭了呢?
我们来看下面这个例子:
// channel 练习
func main() {ch1 := make(chan int)ch2 := make(chan int)// 开启goroutine将0~100的数发送到ch1中go func() {for i := 0; i < 100; i++ {ch1 <- i}close(ch1)}()// 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中go func() {for {i, ok := <-ch1 // 通道关闭后再取值ok=falseif !ok {break}ch2 <- i * i}close(ch2)}()// 在主goroutine中从ch2中接收值打印for i := range ch2 { // 通道关闭后会退出for range循环fmt.Println(i)}
}
从上面的例子中我们看到有两种方式在接收值的时候判断通道是否被关闭,我们通常使用的是for range的方式。
1.1.9单向通道
有的时候我们会将通道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中使用通道都会对其进行限制,比如限制通道在函数中只能发送或只能接收。
Go语言中提供了单向通道来处理这种情况。例如,我们把上面的例子改造如下:
func counter(out chan<- int) {for i := 0; i < 100; i++ {out <- i}close(out)
}func squarer(out chan<- int, in <-chan int) {for i := range in {out <- i * i}close(out)
}
func printer(in <-chan int) {for i := range in {fmt.Println(i)}
}func main() {ch1 := make(chan int)ch2 := make(chan int)go counter(ch1)go squarer(ch2, ch1)printer(ch2)
}
其中,
1.chan<- int是一个只能发送的通道,可以发送但是不能接收;
2.<-chan int是一个只能接收的通道,可以接收但是不能发送。
在函数传参及任何赋值操作中将双向通道转换为单向通道是可以的,但反过来是不可以的。
1.1.10 通道总结
channel常见的异常总结,如下图:
注意:关闭已经关闭的channel也会引发panic。
相关文章:
GO语言网络编程(并发编程)Channel
GO语言网络编程(并发编程)Channel 1、Channel 1.1.1 Channel 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态…...
c++day3
stack.h #ifndef STACK_H #define STACK_H #include <iostream> //#define max 128 using namespace std; class Stack { private:int* stack;//数组指针int top;//栈顶元素int max;//栈容量 public://构造函数Stack();//析构函数~Stack();//定义拷贝构造函数Stack(cons…...
算法通过村第六关-树青铜笔记|中序后序
文章目录 前言1. 树的常见概念2. 树的性质3. 树的定义与存储方式4. 树的遍历方式5. 通过序列构建二叉树5.1 前中序列恢复二叉树5.2 中后序列恢复二叉树 总结 前言 提示:瑞秋是个小甜心,她只喜欢被爱,不懂的去爱人。 --几米《你们 我们 他们》…...
C++动态内存管理+模板
💓博主个人主页:不是笨小孩👀 ⏩专栏分类:数据结构与算法👀 C👀 刷题专栏👀 C语言👀 🚚代码仓库:笨小孩的代码库👀 ⏩社区:不是笨小孩👀 🌹欢迎大…...
SQL 注入漏洞攻击
文章目录 1. 介绍2. 无密码登录3. 无用户名无密码登录4. 合并表获取用户名密码 1. 介绍 假设你用自己的用户名和密码登录了一个付费网站,网站服务器就会查询一下你是不是 VIP 用户,而用户数据都是放在数据库中的,服务器通常都会向数据库进行查…...
一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(四)
之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…...
Transformer 模型中常见的特殊符号
Transformer 模型中常见的特殊符号 通过代码一起理解一下 Transformer 模型中常见的特殊符号, 示例代码, special_tokens{unk_token: [UNK], sep_token: [SEP], pad_token: [PAD], cls_token: [CLS], mask_token: [MASK]}这段代码是定义了一个字典spec…...
C# halcon SubImage的使用
SubImage(HObject imageMinuend, HObject imageSubtrahend, out HObject imageSub, HTuple mult, HTuple add) 公式 x1imageMinuend此行此列的灰度 x2imageSubtrahend此行此列的灰度 则imageSub此行此列的灰度为;(x1-x2)*multadd 溢出裁剪 以byte图为例,小于0&a…...
每天几道Java面试题:异常机制(第三天)
目录 第三幕、第一场)异常机制面试题 友情提醒 背面试题很枯燥,加入一些戏剧场景故事人物来加深记忆。PS:点击文章目录可直接跳转到文章指定位置。 第三幕、 第一场)异常机制面试题 【面试官老吉,面试官潘安,面试者…...
Linux 中的 chattr 命令及示例
Linux 中的chattr命令是一个文件系统命令,用于更改目录中文件的属性。该命令的主要用途是使多个文件无法被超级用户以外的用户更改。管理员表示,众所周知,Linux 是一个多用户操作系统,一个用户有可能删除另一个用户非常关心的文件。为了避免这种情况,Linux 提供了“ chatt…...
LeetCode 2605. Form Smallest Number From Two Digit Arrays【数组,哈希表,枚举;位运算】1241
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
VoxWeekly|The Sandbox 生态周报|20230904
欢迎来到由 The Sandbox 发布的《VoxWeekly》。我们会在每周发布,对上一周 The Sandbox 生态系统所发生的事情进行总结。 如果你喜欢我们内容,欢迎与朋友和家人分享。请订阅我们的 Medium 、关注我们的 Twitter,并加入 Discord 社区…...
antd setFieldsValue 设置初始值无效AutoComplete 设置默认值失败
antd form setFieldsValue 设置初始值无效 解决方案 setTimeout(()>{setFieldsValue(values)},100)antd AutoComplete 设置默认值失败 defaultValue 设置无效 解决方案 设置value,搭配onChange来设置修改...
01-Redis核心数据结构与高性能原理
上一篇: 1.Redis安装 下载地址:http://redis.io/download 安装步骤: # 安装gcc yum install gcc# 把下载好的redis-5.0.3.tar.gz放在/usr/local文件夹下,并解压 wget http://download.redis.io/releases/redis-5.0.3.tar.gz…...
预防Dos攻击
Dos----拒绝服务攻击,一般是构造特殊的输入,使得后台的处理耗时远超正常水平,随着请求越来越多,后台服务越发疲于奔命,最后因资源耗尽,无法再接受新的请求,最终造成拒绝服务的效果。 特殊输入例…...
ant design的文档真的是一坨屎
很多基础设置 高傲的写都不写 要自己去index.d.ts里查 这就算了,为什么还有错的。。。。。 即使因为版本号而不同,起码把差异说明一下吧,直接丢个错的什么意思,。。。。。。。。 没点子功夫还真用不了 文档 进度条 Progress -…...
关于迁移学习的一点理解
举个栗子,老虎图片的数量非常少,可以让网络先学会识别猫的图片 1、预训练模型 内容:利用在 ImageNet1000 数据集训练好的模型,将所需的模型参数下载,嵌入到对应的网络架构中,使用对预训练模型的搭建。目前P…...
【力扣周赛】第 361 场周赛(⭐前缀和+哈希表 树上倍增、LCA⭐)
文章目录 竞赛链接Q1:7020. 统计对称整数的数目竞赛时代码——枚举预处理 Q2:8040. 生成特殊数字的最少操作(倒序遍历、贪心)竞赛时代码——检查0、00、25、50、75 Q3:2845. 统计趣味子数组的数目竞赛时代码——前缀和…...
解决 Android 依赖冲突
解决办法 问题原因就是,各个模块所有的依赖(递归)的 jar 包最后都会加载到安卓的项目中,你可以选择 project 形式查看 External Libraries,都在这了。所以解决问题关键就是干掉冲突,剩下一个就行了…...
前端设计模式基础笔记
前端设计模式是指在前端开发中经常使用的一些解决问题的模式或思想。它们是经过实践证明的最佳实践,可以帮助我们更好地组织和管理我们的代码。 一、单例模式(Singleton Pattern) 单例模式是一种创建型模式,它保证一个类只有一个…...
Python项目开发:Flask基于Python的天气数据可视化平台
目录 步骤一:数据获取 步骤二:设置Flask应用程序 步骤三:处理用户输入和数据可视化 步骤四:渲染HTML模板 总结 在这个数字化时代,数据可视化已经成为我们理解和解释信息的重要手段。在这个项目中,我们…...
Dell 服务器常见报错信息汇总
Dell 服务器常见报错汇总 如果有别的报错信息欢迎补充...
算法通关村-----贪心面试大热门之区间问题
判断区间是否重叠 问题描述 给定一个会议时间安排数组intervals,每个会议时间都包括开始时间和结束时间,intervals[i] [starti,endi],请你判断一个人是否能够参加这里面的全部会议。详见leetcode252 问题分析 先将会议安排数组按照开始时间排序&…...
OAK相机:自动或手动设置相机参数
OAK相机:自动或手动设置相机参数 硬件软件 硬件 使用硬件如下: 4✖️ov9782相机OAK-FFC-4P驱动板 硬件接线参考博主的一篇博客:OAK相机:多相机硬件同步拍摄 软件 博主使用的是Ubuntu18.04系统,首先配置所需的pytho…...
百家宴焕新上市,持续深耕100-300元价位段
执笔 | 尼 奥 编辑 | 古利特 4月8日,长江酒道曾在《百家宴谋划“晋级”之路,多措并举切分宴席市场“蛋糕”》一文中提到:“百家宴主力新品即将登场,市场政策灵活焕新。” 如今,百家宴新品及市场新政,正…...
Linux Debian12使用git将本地项目上传到码云(gitee)远程仓库
一、注册码云gitee账号 这个可以参考其他教程,本文不做介绍。 gitee官网:https://gitee.com/ 二、Linux Debian12安装git 如果Linux系统没有安装git,可以使用下面命令安装git sudo apt install git 三、gitee新建仓库 我这只做测试&…...
电子烟行业常用的英文表达
1. 电子烟的各种表达 a) 电子烟 i. Electronic-cigarette, ii. Electronic smoke, iii. electronic cigarettes iv. Electric cigarette, v. E-Cigarettes vi. e-cigarette, vii. e-Cig viii. E cigar,e-cigar 电子烟雪茄 2. 电子烟特指词汇及衍生 a) VAPE i. Vapo…...
【SpringMvc 丨跨域】
Spring MVC 支持跨域处理(CORS)。 CORS 简介处理CORS 过滤器CrossOrigin注解java配置xml配置 主页传送门:📀 传送 简介 跨域是指在浏览器的同源策略下,不能执行其他网站的脚本。它是由浏览器的安全限制造成的…...
【C语言】【strlen函数的使用与模拟实现】
1.strlen函数的使用和模拟实现 1.1使用: size_t strlen(const char* str)返回类型为无符号整型,参数是字符指针 计算的是字符串中到“\0"之前的字符个数 1.2模拟实现: 方法一:计数器式遍历 #include<stdio.h> #in…...
类和对象【基础概念】
全文目录 类的定义定义方式 类的访问限定符封装(面向对象的三大特性之一) 类对象模型类对象的存储方式类对象的大小计算 this指针this指针的特性**this指针可以为空吗?** 类的定义 在C中,C语言中的结构体struct中除了定义变量外还…...
国务院网站官网建设部/长春百度网站优化
在ThinkPHP3.2框架中,默认已经没有Public文件夹了。其中对于__PUBLIC__的定义也需要重新定义。这给笔者造成了很长时间的困扰,现在这个问题终于解决,分享出来给大家参照一下。 在ThinkPHP中config文件中进行一下配置即可。 //重定义网站的一…...
可以做代销的网站都有哪些/网站品牌推广公司
欢迎关注我的专栏( つ•̀ω•́)つ【人工智能通识】当用户请求一个网页的时候,如何让服务器把网页文件发送给用户?文件服务器首先我们要知道,用户在浏览器中看到的页面其实就是一个.html文件,就是我们上一篇文章时候撰写的...代码…...
自己做网站原始代码/个人博客搭建
这两天在写HTML页面今天要实现一个手机用户访问页面的时候,如果页面中有电话号码,点击可以打电话或者是发信息,之前没做过今天刚听说感觉很高大上会很难,实际上简单的让我内牛满面啊,, 小婊砸 (*ο*) &…...
网站建设:/潍坊seo关键词排名
API Testing 入门基础系列 之 API Testing 9 - REST和RESTFull API的区别 这两个概念容易混淆,可能会在面试过程中被问到,所以单独拿出来了解一下。 REST是REpresentational State Transfer的缩写,表述性状态转移。它是一种架构风格&#x…...
360免费建站永久免费/疫情二十条优化措施
时常想对工作,技术上的知识做一些总结,囿于工作繁杂,思路又常常信马由缰,总是虎头蛇尾。后来看到阮一峰老师的每周分享,感觉这种形式挺好:形式不受拘泥,题材灵活可以涉及技术生活各方面。 成功就…...
没有域名网站吗/找回今日头条
SuperIO 2.1下载 一、SuperIO 的特点: 1) 能够很快的构建自己的通讯平台软件,包括主程序。 2) 设备模块化开发,通过配制文件挂载,即可在平台软件下运行。 3) 设备模块同时支持COM和TCP两种通讯方式,可以自由切换…...