深入理解Go语言中的并发编程【30】【多路复用】

news2024/9/22 9:31:36

文章目录

    • 多路复用


多路复用

  操作系统级的I/O模型有:

  • 阻塞I/O
  • 非阻塞I/O
  • 信号驱动I/O
  • 异步I/O
  • 多路复用I/O
      Linux下,一切皆文件。包括普通文件、目录文件、字符设备文件(键盘、鼠标)、块设备文件(硬盘、光驱)、套接字socket等等。文件描述符(File descriptor,FD)是访问文件资源的抽象句柄,读写文件都要通过它。文件描述符就是个非负整数,每个进程默认都会打开3个文件描述符:0标准输入、1标准输出、2标准错误。由于内存限制,文件描述符是有上限的,可通过ulimit –n查看,文件描述符用完后应及时关闭。

阻塞I/O

在这里插入图片描述

非阻塞I/O

在这里插入图片描述

  read和write默认是阻塞模式。

ssize_t read(int fd, void *buf, size_t count); 
ssize_t write(int fd, const void *buf, size_t nbytes);

  通过系统调用fcntl可将文件描述符设置成非阻塞模式。

int flags = fcntl(fd, F_GETFL, 0); 
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

多路复用I/O
  select系统调用可同时监听1024个文件描述符的可读或可写状态。poll用链表存储文件描述符,摆脱了1024的上限。各操作系统实现了自己的I/O多路复用函数,如epoll、 evport 和kqueue等。

在这里插入图片描述

在这里插入图片描述

  go多路复用函数以netpoll为前缀,针对不同的操作系统做了不同的封装,以达到最优的性能。在编译go语言时会根据目标平台选择特定的分支进行编译。

在这里插入图片描述

  利用go channel的多路复用实现倒计时发射的demo。

在这里插入图片描述

package main

import (
	"fmt"
	"os"
	"time"
)

//倒计时
func countDown(countCh chan int, n int, finishCh chan struct{}) {
	if n <= 0 { //从n开始倒数
		return
	}
	ticker := time.NewTicker(1 * time.Second) //创建一个周期性的定时器,每隔1秒执行一次
	for {
		countCh <- n //把n放入管道
		<-ticker.C   //等1秒钟
		n--          //n减1
		if n <= 0 {  //n减到0时退出
			ticker.Stop()          //停止定时器
			finishCh <- struct{}{} //成功结束
			break                  //退出for循环
		}
	}
}

//中止
func abort(ch chan struct{}) {
	buffer := make([]byte, 1)
	os.Stdin.Read(buffer) //阻塞式IO,如果标准输入里没数据,该行一直阻塞。注意在键盘上敲完后要按下Enter才会把输入发给Stdin
	ch <- struct{}{}
}

func main() {
	countCh := make(chan int)
	finishCh := make(chan struct{})
	go countDown(countCh, 10, finishCh) //开一个子协程,去往countCh和finishCh里放数据
	abortCh := make(chan struct{})
	go abort(abortCh) //开一个子协程,去往abortCh里放数据

LOOP:
	for { //循环监听
		select { //同时监听3个channel,谁先准备好就执行谁,然后进入下一次for循环
		case n := <-countCh:
			fmt.Println(n)
		case <-finishCh:
			fmt.Println("finish")
			break LOOP //退出for循环。在使用for select时,单独一个break不能退出for循环
		case <-abortCh:
			fmt.Println("abort")
			break LOOP //退出for循环
		}
	}
}

timeout实现

  • ctx,cancel:=context.WithCancel(context.Background())调用cancel()将关闭ctx.Done()对应的管道

  • ctx,cancel:=context.WithTimeout(context.Background(),time.Microsecond*100)调用cancel或者到达超时时间都将关闭ctx.Done()对应的管道

  • ctx.Done()管道关闭后读操作将立即返回

  函数超时控制的4种实现。

package main

import (
	"context"
	"fmt"
	"time"
)

const (
	WorkUseTime = 500 * time.Millisecond
	Timeout     = 100 * time.Millisecond
)

//模拟一个耗时较长的任务
func LongTimeWork() {
	time.Sleep(WorkUseTime)
	return
}

//模拟一个接口处理函数
func Handle1() {
	deadline := make(chan struct{}, 1)
	workDone := make(chan struct{}, 1)
	go func() { //把要控制超时的函数放到一个协程里
		LongTimeWork()
		workDone <- struct{}{}
	}()
	go func() { //把要控制超时的函数放到一个协程里
		time.Sleep(Timeout)
		deadline <- struct{}{}
	}()
	select { //下面的case只执行最早到来的那一个
	case <-workDone:
		fmt.Println("LongTimeWork return")
	case <-deadline:
		fmt.Println("LongTimeWork timeout")
	}
}

//模拟一个接口处理函数
func Handle2() {
	workDone := make(chan struct{}, 1)
	go func() { //把要控制超时的函数放到一个协程里
		LongTimeWork()
		workDone <- struct{}{}
	}()
	select { //下面的case只执行最早到来的那一个
	case <-workDone:
		fmt.Println("LongTimeWork return")
	case <-time.After(Timeout):
		fmt.Println("LongTimeWork timeout")
	}
}

//模拟一个接口处理函数
func Handle3() {
	//通过显式sleep再调用cancle()来实现对函数的超时控制
	//调用cancel()将关闭ctx.Done()对应的管道
	ctx, cancel := context.WithCancel(context.Background())

	workDone := make(chan struct{}, 1)
	go func() { //把要控制超时的函数放到一个协程里
		LongTimeWork()
		workDone <- struct{}{}
	}()

	go func() {
		//100毫秒后调用cancel(),关闭ctx.Done()
		time.Sleep(Timeout)
		cancel()
	}()

	select { //下面的case只执行最早到来的那一个
	case <-workDone:
		fmt.Println("LongTimeWork return")
	case <-ctx.Done(): //ctx.Done()是一个管道,调用了cancel()都会关闭这个管道,然后读操作就会立即返回
		fmt.Println("LongTimeWork timeout")
	}
}//LongTimeWork timeout

//模拟一个接口处理函数
func Handle4() {
	//借助于带超时的context来实现对函数的超时控制
	//调用cancel()或到达超时时间都将关闭ctx.Done()对应的管道
	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
	defer cancel() //纯粹出于良好习惯,函数退出前调用cancel()
	workDone := make(chan struct{}, 1)
	go func() { //把要控制超时的函数放到一个协程里
		LongTimeWork()
		workDone <- struct{}{}
	}()
	select { //下面的case只执行最早到来的那一个
	case <-workDone:
		fmt.Println("LongTimeWork return")
	case <-ctx.Done(): //ctx.Done()是一个管道,context超时或者调用了cancel()都会关闭这个管道,然后读操作就会立即返回
		fmt.Println("LongTimeWork timeout")
	}
}

func main() {
	Handle1()
	Handle2()
	Handle3()
	Handle4()
}

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

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

相关文章

【LeetCode】按摩师

按摩师 题目描述算法分析编程代码 链接: 按摩师 题目描述 算法分析 编程代码 class Solution { public:int massage(vector<int>& nums) {int n nums.size();if(n 0) return 0;vector<int> f(n);auto g f;f[0] nums[0];for(int i 1;i<n;i){f[i] g[i…

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能

实现效果 点击checkBox1或者直接在第一列列表头点击即可实现 代码实现 我的datagridview叫dgv 我在datagridview已经默认添加了一个DataGridViewCheckBoxColumn&#xff0c;勾选时value为1&#xff0c;不勾选时value为0 第一种通过可视化拖动一个checkBox来实现 拖动组…

ElasticSearch单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

餐饮管理系统ssm酒店饭店仓库进销存jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 餐饮管理系统ssm 系统有1权限&#xff1a;管理员 二…

使用MethodInterceptor和ResponseBodyAdvice做分页处理

目录 一、需求 二、代码实现 父pom文件 pom文件 配置文件 手动注册SqlSessionFactory&#xff08;MyBatisConfig &#xff09; 对象 实体类Users 抽象类AbstractQuery 查询参数类UsersQuery 三层架构 UsersController UsersServiceImpl UsersMapper UsersMapper.…

C++项目:在线五子棋对战网页版--session管理模块开发

session 在WEB开发中&#xff0c;HTTP协议是⼀种⽆状态短链接的协议&#xff0c;这就导致⼀个客⼾端连接到服务器上之后&#xff0c;服务器不知道当前的连接对应的是哪个用户&#xff0c;也不知道客⼾端是否登录成功&#xff0c;这时候为客⼾端提所有服务是不合理的。因此&am…

微信昵称后面的“小耳朵”,原来有这么多用处,让我带你涨知识

微信昵称后面的“小耳朵”&#xff0c;原来有这么多用处&#xff0c;让我带你涨知识 大家都知道&#xff0c;在微信昵称后面加上一个"小耳朵"符号是一种常见的表达方式&#xff0c;但你知道吗&#xff1f;这个看似简单的符号其实有着丰富的用处和意义。让我带你了解…

java中io流、属性集Properties、缓冲流、转换流、序列化和反序列化、打印流、网络编程(TCP通信程序、文件复制案例、文件上传案例、B/S服务案例)

IO流&#xff1a; io流中i表示input输入&#xff0c;o表示output输出&#xff0c;流表示数据&#xff08;字符&#xff0c;字节&#xff0c;1个字符2个字节8个位&#xff09;&#xff1b;这里的输入输出是以内存为基础&#xff0c;将数据从内存中输出到硬盘的过程称为输出&…

CMSIS—OS(V1/V2)

在RTOS基础上再封装一层API。 更换项目中所使用到的RTOS。 例如将freertos项目替换为ucos RTX liteos等其他RTOS。 只需更改该CMSIS-OS的API所调用的RTOS的API。 更换RTOS的意义何在&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&am…

函数的学习

函数学习 最后附上全部java源码&#xff0c;可自行下载学习 文章目录 函数入门函数重载函数可变个数参数foreach输出传参 基本数据类型传参_引用数据类型文件夹展示所有里面的文件使用递归算法展示文件夹下所有文件1加到100的递归调用下载链接 函数入门 函数重载 public class…

为什么企业一定要走标准化、体系化的道路?

企业实行标准化、体系化道路&#xff0c;有几个重要原因&#xff1a; 1.一致性和质量&#xff1a;标准化流程和系统可确保任务始终如一且高质量地执行。这种一致性对于提供满足客户期望的产品和服务至关重要&#xff0c;从而在客户之间建立信任和忠诚度。 2.效率和生产力&…

强化安全防线:迅软科技助力美容院提升终端安全管理水平

某美容院专注于皮肤抗衰老研究与美容领域服务,业务主要包含轮廊塑型、自体脂肪、五官雕塑等,业务涵盖中国、香港、美国、韩国等多个国家及地区提倡以积极、健康、理智的美学观点,以完善的美容院管理,过硬的技术设备,为消费者提供个性化漂亮服务。 美容院的核心诉求 美容院新产…

【攻防世界】command_execution

题目再现 小宁写了个ping功能,但没有写waf,X老师告诉她这是非常危险的&#xff0c;你知道为什么吗。 题目分析 本题目说没有写WAF&#xff0c;然后可以执行Linux经典代码PING&#xff0c;我猜测到服务器不会校验我所注入的代码&#xff0c;我利用串行执行符&&进行测…

查看CentOS版本及系统位数与设置CentOS 7.9 2009 防火墙配置放开端口的命令与过程

一、查看CentOS版本及系统位数 1.1 命令汇总 //1、安装redhat-lsb yum install -y redhat-lsb//2、查看系统版本信息 lsb_release -a //3、查看系统位数 getconf LONG_BIT1.2 截图 二、设置CentOS7.9 2009 防火墙配置放开端口 2.1 命令汇总 //禁止防火墙开机启动。这种方法方…

侯捷C++高级编程(下)

对于1个类要么像指针要么像函数 主题1:转换函数 转换函数 /** 1. 转换函数没有返回类型* 2. 转换函数一般需要加上const*/ class Fraction { public:Fraction(int num,int den1):m(num),n(den){cout<<"Fraction(int num,int den1): m/n "<< m/n<&…

[Leetcode - Python]704.二分查找(Easy)

1. 题目&#xff1a; 704.二分查找&#xff08;Easy&#xff09; 1代码&#xff1a; class Solution:def search(self, nums: List[int], target: int) -> int:left , right 0 ,len(nums)-1while left < right :mid (leftright)//2 # // 取整除&#xff0c;向…

Windows 安装 pandoc 将 jupyter 导出 pdf 文件

Windows 安装 pandoc 将 jupyter 导出 pdf 文件 1. 下载 pandoc 安装文件2. 安装 pandoc3. 安装 nbconvert4. 使用 pandoc 1. 下载 pandoc 安装文件 访问 https://github.com/jgm/pandoc/releases&#xff0c;下载最新版安装文件&#xff0c;例如&#xff0c;3.1.6.1 版&#…

【Kubernetes】Kubernetes之Pod详解

Pod 一、 Pod1. Pod 基础概念2. 在 Kubrenetes 集群中 Pod 使用方式2.1 pasue 容器2.2 kubernetes 中的 pause 容器提供的功能 3. Pod 的概念和结构组成4. Pod 的分类5. Pod 容器的分类5.1 基础容器&#xff08;infrastructure container&#xff09;5.2 初始化容器&#xff08…

【效率提升—Python脚本】根据Verilog文件自动生成tb文件

文章目录 Verilog端口文件&#xff08;仅做示范用&#xff09;对应的tb文件相应代码 在数字IC设计过程中&#xff0c;根据顶层生成testbench时存在很多重复性工作&#xff0c;因此为了提高工作效率&#xff0c;特地开发此脚本。 Verilog端口文件&#xff08;仅做示范用&#xf…

Centos7离线安装MySQL8

1、下载MySQL https://downloads.mysql.com/archives/community/ 2、下载完毕后&#xff0c;上传到Centos&#xff0c;解压 tar -xf mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar 3、逐条执行安装命令 rpm -ivh mysql-community-common-8.0.33-1.el7.x86_64.rpm rpm -ivh …