44-Golang中的channel

news2024/11/26 14:37:09

Golang中的channel

    • 为什么要使用channel
    • channel的介绍
    • channel的基本使用
      • 定义/声明channel
    • 管道的遍历和关闭
      • channel的关闭
      • channel的遍历
    • goroutine和channel结合
      • 应用实例1
      • 应用实例2
      • 案例
    • 注意事项

为什么要使用channel

前面使用全局变量加锁同步来解决goroutine的通讯,但不完美

  • 1.主线程在等待所有goroutine全部完成时间很难确定,我们这里设置10秒,仅仅是过段
  • 2.如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有routine处于工作状态,这时也会随主线程的退出而销毁
  • 3.通过全局白能量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作
  • 4.上面种种分析都在互换一个新的通讯机制-----channel

channel的介绍

  • 1.channel本质就是一个数据结构-队列
  • 2.数据是先进先出
  • 3.线程安全,多goroutine访问时,不需要加锁,就是说channel本身就是线程安全的
  • 4.channel是有类型的,一个string的channel只能存放string类型数据
    在这里插入图片描述

channel的基本使用

定义/声明channel

var 变量名chan数据类型

举例:

var intChan chan int (intChan用于存放int数据)

var mapChan chan map[int]ssting (mapChan用于存放map[int]string类型)

var perChan chan Person

var perChan2 chan *Person

说明:

channel是引用类型

channel必须初始化才能写入数据,即make后才能使用

管道是有类型的,intChan只能写入整数

package main

import "fmt"

func main() {
	//演示一下管道的使用
	//创建一个可以存放三个int类型的俄管道
	var intChan chan int
	intChan = make(chan int, 3)

	//看看intChan是什么
	fmt.Printf("intChan的值=%v intChan本身的地址=%p\n", intChan, &intChan)

	//向管道写入数据
	intChan <- 10
	num := 211
	intChan <- num

	//看看管道的长度和cap(容量)
	fmt.Printf("channel len = %v cap=%v \n", len(intChan), cap(intChan))

	//从管道中读取数据
	var num2 int
	num2 = <-intChan
	fmt.Println("num2=", num2)
	fmt.Printf("channel len =%v cap=%v \n", len(intChan), cap(intChan))

	//在没有使用协程的情况下,如果我们管道数据已经全部取出,在取就会报告deadlock
}
/*
intChan的值=0xc00010e080 intChan本身的地址=0xc000006028
channel len = 2 cap=3 
num2= 10              
channel len =1 cap=3  
*/

管道的遍历和关闭

channel的关闭

使用内置函数close可以关闭channel,当channel关闭后,就不能再想channel写数据了,但是仍然可以从给channel读取数据

channel的遍历

channel支持for-range的方式进行遍历

1.在遍历时,如果channel没有关闭,则会出现deadlock的错误

2.在遍历时,如果channel已经关闭,则会出现正常遍历数据,遍历完后,就会退出遍历

package main

import "fmt"

func main() {
	intChan := make(chan int, 3)
	intChan <- 100
	intChan <- 200
	close(intChan)
	//这时不能够再写入到channel
	//intChan <- 300
	fmt.Println("okk")
	n1 := <-intChan
	fmt.Println("n1=", n1)

	//遍历管道
	intChan2 := make(chan int, 100)
	for i := 0; i < 100; i++ {
		intChan2 <- i * 2 //放入100个数据到管道
	}
	// 在遍历时,如果channel没有关闭,责护出现deadlock的错误
	close(intChan2)
	for v := range intChan2 {
		fmt.Println("v=", v)
		
	}
    
}

goroutine和channel结合

应用实例1

在这里插入图片描述

在这里插入图片描述

package main

import (
	"fmt"
	"time"
)

func writeData(intChan chan int) {
	for i := 1; i < 50; i++ {
		//放入数据
		intChan <- i
		fmt.Println("writeData", i)
		time.Sleep(time.Second)
	}
	close(intChan) //关闭
}

//read data
func readData(intChan chan int, exitChan chan bool) {
	for {
		v, ok := <-intChan
		if !ok {
			break
		}
		time.Sleep(time.Second)
		fmt.Printf("readData读到数据=%v\n", v)
	}
	//readData读取完数据后,即任务完成
	exitChan <- true
	close(exitChan)
}

func main() {
	//创建两个管道
	intChan := make(chan int, 50)
	exitChan := make(chan bool, 1)

	go writeData(intChan)
	go readData(intChan, exitChan)

	//time.Sleep(time.Second * 10)
	for {
		_, ok := <-exitChan
		if !ok {
			break
		}
	}
}

应用实例2

如果只是向管道写入数据,而没有读取,就会出现阻塞而dead lock,原因是intChan容量是10,而带点吗writeData会写入50个数据,因此就会阻塞在writeData的ch<-i

案例

在这里插入图片描述

package main

import "fmt"

func putNum(intChan chan int) {
	for i := 1; i <= 8000; i++ {
		intChan <- i
	}
	//关闭intChan
	close(intChan)
}

//开启四个协程,从intChan取出数据,并判断是否为素数
//如果是,就放入到primeChan
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
	//使用for循环
	var flag bool
	for {
		num, ok := <-intChan
		if !ok {
			break
		}
		flag = true //假定是素数
		//判断num是不是素数
		for i := 2; i < num; i++ {
			if num%i == 0 { //说明该num不是素数
				flag = false
				break
			}
		}
		if flag {
			//将这个数就放入到primeChan
			primeChan <- num
		}
	}
	fmt.Println("有一个primeNum协程因为取不到数据,退出")
	//这里还不能关闭primeChan
	//向exitChan写入true
	exitChan <- true
}

func main() {
	intChan := make(chan int, 1000)
	primeChan := make(chan int, 2000) //放入结果
	//标识退出的管道
	exitChan := make(chan bool, 4)

	//开启一个协程,想in特产放入1-8000个数
	go putNum(intChan)
	//开启四个协程,从intChan取出数据,并判断是否为素数
	//如果是,就放入到primeChan
	for i := 0; i < 4; i++ {
		go primeNum(intChan, primeChan, exitChan)
	}

	//这里进行主线程处理
	go func() {
		for i := 0; i < 4; i++ {
			<-exitChan
		}

		//当我们从exitChan,去出了4个结果,就可以放心关闭primeChan
		close(primeChan)
	}()

	//遍历primeNum,把结果输出
	for {
		res, ok := <-primeChan
		if !ok {
			break
		}
		//将结果输出
		fmt.Printf("素数=%d\n", res)
	}
	fmt.Println("main线程退出")
}

注意事项

  • 1.channel可以声明为只读,或者只写性质
  • 2.channel只读和只写的最佳实践案例
package main

import "fmt"

func main() {
	//管道可以声明为只读或者只写
	//默认情况下,管道是双向的
	//var chan1 chan int

	//声明为只写
	var chan2 chan<- int
	chan2 = make(chan int, 3)
	chan2 <- 20
	//num := <-chan2
	fmt.Println("chan2=", chan2)

	//声明为只读
	var chan3 <-chan int
	num2 := <-chan3
	fmt.Println("num2=", num2)
}

  • 3.使用select可以解决从管道取数据的阻塞问题
  • 4.goroutine中使用recover,解决携程中出现panic,导致程序奔溃问题
    • 说明,如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成整个程序崩溃,这是我们可以在goroutine中使用recover来捕获panic,进行处理,这样及时这个协程发生的问题,但是主线程仍然不受影响,

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式—适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式&#xff0c;它结合了两个独立接口的功能。这种模式涉及到一个单一的类&#xff0c;该类负责加入独立的或不兼容的接口功能。举个真实的例子&#xff0c…

【操作系统】如何排查死锁?

【操作系统】如何排查死锁&#xff1f; 文章目录【操作系统】如何排查死锁&#xff1f;死锁的概念死锁的排查工具排查工具 1&#xff1a;jstack排查工具 2&#xff1a;jconsole死锁的发生条件互斥条件持有并等待条件不可剥夺条件环路等待条件避免死锁问题的发生总结死锁的概念 …

TCP、UDP

TCP和UDPTCP报头三次握手&#xff0c;四次挥手确认机制&#xff08;重传ARQ&#xff09;重传机制拥塞控制&#xff08;慢开始-拥塞避免&#xff0c;快重传、快恢复&#xff09;流量控制&#xff08;滑动窗口&#xff09;差错控制&#xff08;校验和&#xff09;UDP报头TCP和UDP…

Qt之高仿QQ系统设置界面

QQ或360安全卫士的设置界面都是非常有特点的,所有的配置项都在一个垂直的ScrollArea中,但是又能通过左侧的导航栏点击定位。这样做的好处是既方便查看指定配置项,又方便查看所有配置项。 一.效果 下面左边是当前最新版QQ的系统设置界面,右边是我的高仿版本,几乎一毛一样…

JVM初步理解浅析

一、JVM的位置 JVM的位置 JVM在操作系统的上一层&#xff0c;是运行在操作系统上的。JRE是运行环境&#xff0c;而JVM是包含在JRE中 二、JVM体系结构 垃圾回收主要在方法区和堆&#xff0c;所以”JVM调优“大部分也是发生在方法区和堆中 可以说调优就是发生在堆中&#xf…

国外seo比较好的优化方法有哪些?

随着互联网的不断发展&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;变得越来越重要。 对于国外市场&#xff0c;Google搜索引擎是最为重要的搜索引擎之一&#xff0c; 因此在优化国外网站时&#xff0c;需要将Google SEO优化作为首要任务。 关键词研究和优化 在进行…

Windows逆向安全(一)C与汇编的关系

前言 逆向是一种新型的思维模式也是软件开发领域中极为重要的技术&#xff0c;涵盖各种维度去深挖软件架构的本质和操作系统原理&#xff0c;学习逆向后可以在各领域中发挥至关重要的作用&#xff0c;其中包括黑灰色&#xff0c;安全开发&#xff0c;客户端安全&#xff0c;物…

没有对象感,沟通太费劲

沟通中最重要的感觉&#xff1a;对象感&#xff01; 要沟通的是谁&#xff1f;以啥方式最好&#xff1f; 趣讲大白话&#xff1a;蹲着跟小孩说话 【趣讲信息科技100期】 ******************************* 对象感是沟通者必须训练和提升的 是换位思考的一种能力 以便跟沟通对象进…

【虚拟工厂】SCL编写<机械手加盖模块>应用

使用scl来编写实虚拟工场中的一个机械手加盖应用项目 文章目录 目录 文章目录 前言 1.机械手加盖场景 2.了解各部分功能 3.命名变量找出输入输出 4.在博图建立变量 二、编写思路 1.分析 2.使用小模块化来编写 3.确定编程思路 三、编程 1.上料部分 2.机械手部分 3…

【数据结构】线性表和顺序表

Yan-英杰的主页 悟已往之不谏 知来者之可追 目录 1.线性表 2.顺序表 2.1 静态顺序表 2.2 动态顺序表 2.3移除元素 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线…

新C++(14):移动语义与右值引用

当你在学习语言的时候&#xff0c;是否经常听到过一种说法,""左边的叫做左值&#xff0c;""右边的叫做右值。这句话对吗&#xff1f;从某种意义上来说&#xff0c;这句话只是说对了一部分。---前言一、什么是左右值?通常认为:左值是一个表示数据的表达式(…

Git版本控制管理

Git日志记录查看日志获取执行过的命令查看每一次提交记录比较文件差异还原文件git远程仓库克隆远程仓库移除无效的远程仓库Git远程仓库推送、抓送&#xff0c;和拉取Git远程仓库多人协作冲突问题Git远程仓库SSH协议推送Git分支查看分支创建分支修改分支切换分支推送至远程仓库分…

Python3实现“美颜”功能

导语利用Python实现美颜。。。这是之前在GitHub上下载的一个项目。。。似乎有些日子了。。。所以暂时找不到原项目的链接了。。。今天抽空看了下它源代码的主要思想&#xff0c;似乎挺简单的。。。于是决定用Python3自己复现一下。。。T_T感觉还是挺有趣的。。。Just have a tr…

源码分析Spring @Configuration注解如何巧夺天空,偷梁换柱。

前言 回想起五年前的一次面试&#xff0c;面试官问Configuration注解和Component注解有什么区别&#xff1f;记得当时的回答是&#xff1a; 相同点&#xff1a;Configuration注解继承于Component注解&#xff0c;都可以用来通过ClassPathBeanDefinitionScanner装载Spring bean…

IT服务发布管理过程文件

目的 规范发布管理的提交、审批、沟通、测试、回滚、实施等活动。 范围 适用于我公司的IT服务管理重大变更的内、外部发布。 术语定义 发布&#xff1a;将一个或多个变更交付、分发到实际运行环境中并可对其进行追溯。非项目的IT服务重大变更需要遵循本过程进行发布。发布主要包…

论文投稿指南——中文核心期刊推荐(工业经济)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

使用TorchGeo进行地理空间深度学习

前言TorchGeo是一个PyTorch域库&#xff0c;提供特定于地理空间数据的数据集、采样器、转换和预训练模型。https://github.com/microsoft/torchgeo几十年来&#xff0c;地球观测卫星、飞机和最近的无人机平台一直在收集越来越多的地球表面图像。有了关于季节和长期趋势的信息&a…

【算法】算法基础入门详解:轻松理解和运用基础算法

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…

查找Pycharm跑代码下载模型存放位置以及有关模型下载小技巧(model_name_or_path参数)

目录一、前言二、发现问题三、删除这些模型方法一&#xff1a;直接删除注意方法二&#xff1a;代码删除一、前言 当服务器连不上&#xff0c;只能在本地跑代码时需要使用***预训练语言模型进行处理 免不了需要把模型下载到本地 时间一长就会发现C盘容量不够 二、发现问题 正…

c++11 标准模板(STL)(std::unordered_map)(九)

定义于头文件 <unordered_map> template< class Key, class T, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator< std::pair<const Key, T> > > class unordered…