深入解析Go语言Channel:源码剖析与并发读写机制
文章目录
- Channel的内部结构
- Channel的创建过程
- 有缓冲Channel的并发读写机制
- 同时读写的可能性
- 发送操作的实现
- 接收操作的实现
- 并发读写的核心机制解析
- 互斥锁保护
- 环形缓冲区
- 等待队列
- 直接传递优化
- Goroutine调度
- 实例分析:有缓冲Channel的并发读写
- 性能优化与最佳实践
- 缓冲区大小的选择
- 适合使用有缓冲Channel的场景
- 使用Select优化Channel操作
- 常见陷阱和注意事项
- 死锁
- Goroutine泄漏
- 关闭Channel的最佳实践
- 高级应用示例
- 限流器实现
- 工作池模式
在Go语言的并发编程模型中,Channel是一个核心概念,它优雅地实现了CSP(Communicating Sequential Processes,通信顺序进程)理念中"通过通信来共享内存,而不是通过共享内存来通信"的思想。本文将从源码层面深入剖析Go Channel的实现机制,特别关注有缓冲Channel的并发读写原理。
Channel的内部结构
要理解Channel的工作原理,首先需要了解其底层实现。在Go运行时(src/runtime/chan.go
)中,Channel通过hchan
结构体实现:
type hchan struct {qcount uint // 当前队列中的元素数量dataqsiz uint // 循环队列的大小(容量)buf unsafe.Pointer // 指向大小为dataqsiz的循环队列elemsize uint16 // 元素类型大小closed uint32 // 非零表示channel已关闭elemtype *_type // 元素类型sendx uint // 发送操作的索引位置recvx uint // 接收操作的索引位置recvq waitq // 接收者等待队列(阻塞在接收操作的goroutine)sendq waitq // 发送者等待队列(阻塞在发送操作的goroutine)lock mutex // 互斥锁,保护hchan中的所有字段
}
这个结构包含了Channel的核心组件:一个用于存储数据的循环队列、两个等待队列(分别用于存储因发送或接收而阻塞的goroutine)以及一个互斥锁来保证操作的并发安全性。
Channel的创建过程
当我们调用make(chan T, size)
时,Go运行时会调用runtime.makechan
函数:
func makechan(t *chantype, size int) *hchan {elem := t.elem// 计算并检查内存需求mem, overflow := math.MulUintptr(elem.size, uintptr(size))if overflow || mem > maxAlloc-hchanSize || size < 0 {panic(plainError("makechan: size out of range"))}var c *hchanswitch {case mem == 0:// 队列大小为零(无缓冲channel)c = (*hchan)(mallocgc(hchanSize, nil, true))c.buf = c.raceaddr()case elem.ptrdata == 0:// 元素不包含指针时的优化分配c = (*hchan)(mallocgc(hchanSize+mem, nil, true))c.buf = add(unsafe.Pointer(c), hchanSize)default:// 元素包含指针的标准分配c = new(hchan)c.buf = mallocgc(mem, elem, true)}c.elemsize = uint16(elem.size)c.elemtype = elemc.dataqsiz = uint(size)return c
}
这个函数根据元素类型和缓冲区大小分配内存,并初始化hchan
结构体的各个字段。
有缓冲Channel的并发读写机制
同时读写的可能性
有缓冲的Channel是否可以同时读写?
当我们说Channel可以"同时读写"时,实际指的是:
- 并发请求层面:多个goroutine可以同时发起对Channel的读写请求。这些goroutine确实在并发执行,可能在不同的CPU核心上运行。
- 操作执行层面:尽管多个goroutine并发发起请求,但由于互斥锁的存在,这些读写操作在Channel内部会被串行化处理。每次只有一个goroutine能获得锁并执行其操作。
- 用户感知层面:对于使用Channel的开发者来说,他们不需要添加额外的同步机制。Channel内部的锁对用户是透明的,使得Channel在使用上看起来支持"同时"读写。
每个Channel操作大致遵循这个模式:
- 获取Channel的互斥锁
- 执行读/写操作
- 释放互斥锁
但这就像银行办理业务一样,多个客户(goroutine)同时到达银行(发起Channel操作请求),银行有多个柜台(Go调度器可以并发处理多个goroutine),但是每个特定账户(Channel)在任意时刻只能由一个柜员处理(互斥锁)。Go的调度器确保这些操作看起来是并发的,即使它们在底层是串行执行的。
发送操作的实现
Channel的发送操作(ch <- v
)通过runtime.chansend
函数实现:
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {// 获取channel锁lock(&c.lock)// 检查channel是否已关闭if c.closed != 0 {unlock(&c.lock)panic(plainError("send on closed channel"))}// 快速路径:如果有等待的接收者,直接将数据发送给接收者if sg := c.recvq.dequeue(); sg != nil {send(c, sg, ep, func() { unlock(&c.lock) })return true}// 如果缓冲区未满,将数据放入缓冲区if c.qcount < c.dataqsiz {qp := chanbuf(c, c.sendx)typedmemmove(c.elemtype, qp, ep)c.sendx++if c.sendx == c.dataqsiz {c.sendx = 0}c.qcount++unlock(&c.lock)return true}if !block {unlock(&c.lock)return false}// 缓冲区已满,当前goroutine需要阻塞// 将当前goroutine包装并加入sendq队列gp := getg()mysg := acquireSudog()// 设置sudog的各项属性// ...c.sendq.enqueue(mysg)// 挂起当前goroutinegopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2)// 被唤醒后的操作// ...releaseSudog(mysg)return true
}
接收操作的实现
Channel的接收操作(<-ch
)通过runtime.chanrecv
函数实现:
func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {// 获取channel锁lock(&c.lock)// 如果channel已关闭且缓冲区为空if c.closed != 0 && c.qcount == 0 {unlock(&c.lock)if ep != nil {typedmemclr(c.elemtype, ep)}return true, false}// 快速路径:如果有等待的发送者if sg := c.sendq.dequeue(); sg != nil {// 接收数据并唤醒发送者recv(c, sg, ep, func() { unlock(&c.lock) })return true, true}// 如果缓冲区有数据,直接从缓冲区读取if c.qcount > 0 {qp := chanbuf(c, c.recvx)if ep != nil {typedmemmove(c.elemtype, ep, qp)}typedmemclr(c.elemtype, qp)c.recvx++if c.recvx == c.dataqsiz {c.recvx = 0}c.qcount--// 如果有等待的发送者,现在可以让其发送数据到缓冲区if sg := c.sendq.dequeue(); sg != nil {gp := sg.g// 将发送者的数据放入缓冲区// ...goready(gp, 3)}unlock(&c.lock)return true, true}if !block {unlock(&c.lock)return false, false}// 没有数据可读,当前goroutine需要阻塞// 将当前goroutine包装并加入recvq队列// ...return true, true
}
并发读写的核心机制解析
分析源码后,我们可以看出有缓冲Channel的并发读写机制依赖于以下几个关键点:
互斥锁保护
Channel的所有操作都受到互斥锁(lock
)的保护,确保在任意时刻只有一个goroutine能够修改Channel的内部状态。这个锁是实现并发安全的基础。
环形缓冲区
Channel使用环形缓冲区(由buf
、sendx
和recvx
字段组成)来高效地存储和访问数据:
buf
指向存储元素的内存区域sendx
指示下一次发送操作应该写入的位置recvx
指示下一次接收操作应该读取的位置
当索引达到缓冲区末尾时,会重新从0开始,形成一个循环。
等待队列
当Channel操作无法立即完成时(如发送到已满的Channel或从空Channel接收),当前goroutine会被封装为一个sudog
结构,并放入相应的等待队列:
sendq
存储等待发送数据的goroutinerecvq
存储等待接收数据的goroutine
直接传递优化
如果一个goroutine尝试从Channel接收数据,而此时有另一个goroutine正在等待发送数据,运行时会跳过缓冲区,直接将数据从发送者传递给接收者,这是一种重要的优化。
Goroutine调度
当Channel操作被阻塞时,当前goroutine会被挂起(gopark
),让出CPU时间给其他goroutine。当操作可以继续时(如有新数据可读或新空间可写),被阻塞的goroutine会被唤醒(goready
)。
实例分析:有缓冲Channel的并发读写
以下是一个简单的示例,展示有缓冲Channel的并发读写行为:
func main() {// 创建缓冲区大小为3的channelch := make(chan int, 3)// 启动多个发送者for i := 0; i < 5; i++ {go func(val int) {ch <- valfmt.Printf("发送: %d\n", val)}(i)}// 启动多个接收者for i := 0; i < 5; i++ {go func() {val := <-chfmt.Printf("接收: %d\n", val)}()}// 等待所有goroutine完成time.Sleep(time.Second)
}
执行流程分析如下:
- 初始状态:Channel创建后,缓冲区为空,
sendx = 0, recvx = 0, qcount = 0
。 - 并发发送:
- 前3个发送操作会将数据放入缓冲区,因为缓冲区有足够空间。
- 后2个发送操作会被阻塞,因为缓冲区已满。相应的goroutine会被放入
sendq
队列等待。
- 并发接收:
- 前3个接收操作会从缓冲区读取数据,这会使缓冲区出现空间。
- 当缓冲区有空间时,
sendq
中等待的goroutine会被唤醒,能够继续其发送操作。 - 所有5个接收操作最终都能成功完成。
- 数据传递:尽管有10个goroutine并发操作同一个Channel,但由于互斥锁的存在,这些操作在底层是串行执行的,保证了数据的一致性和完整性。
性能优化与最佳实践
缓冲区大小的选择
有缓冲Channel的缓冲区大小会直接影响性能:
- 过小的缓冲区可能导致频繁的goroutine阻塞和唤醒,增加调度开销。
- 过大的缓冲区会占用更多内存,且可能掩盖程序设计问题(如生产者-消费者速率不匹配)。
- 理想大小应根据应用场景、生产和消费速率差异、延迟要求等因素确定。
适合使用有缓冲Channel的场景
- 速率不匹配:当生产者和消费者的处理速率不同时,缓冲区可以平滑速率差异。
- 突发流量处理:缓冲区可以吸收突发的数据流,避免瞬时压力过大。
- 批量处理:积累一定量的数据后一次性处理,提高处理效率。
- 并发限制:使用固定大小的Channel控制并发goroutine的数量。
使用Select优化Channel操作
select
语句是Channel操作的重要补充,可以实现多Channel监听、超时处理和非阻塞操作:
select {
case data := <-ch1:// 处理来自ch1的数据
case ch2 <- value:// 数据成功发送到ch2
case <-time.After(timeout):// 超时处理
default:// 所有channel操作都会阻塞时执行
}
常见陷阱和注意事项
死锁
以下情况可能导致死锁:
- 在同一个goroutine中对无缓冲Channel进行发送和接收
- 所有goroutine都在等待Channel操作,但没有goroutine能够唤醒它们
- 向已关闭的Channel发送数据(会引发panic)
Goroutine泄漏
如果一个goroutine在等待一个永远不会完成的Channel操作,该goroutine将永远不会被释放,这就是goroutine泄漏。常见原因包括:
- 接收者比发送者少,导致部分发送操作永远阻塞
- 忘记关闭Channel,导致接收者永远等待
关闭Channel的最佳实践
- 通常由发送者负责关闭Channel
- 永远不要关闭接收端的Channel
- 永远不要关闭已关闭的Channel
高级应用示例
限流器实现
利用有缓冲Channel可以轻松实现一个简单的限流器:
type RateLimiter struct {tokens chan struct{}
}func NewRateLimiter(rate int) *RateLimiter {rl := &RateLimiter{tokens: make(chan struct{}, rate),}// 初始填充令牌for i := 0; i < rate; i++ {rl.tokens <- struct{}{}}// 按固定速率补充令牌go func() {ticker := time.NewTicker(time.Second)defer ticker.Stop()for range ticker.C {select {case rl.tokens <- struct{}{}:// 添加令牌成功default:// 令牌桶已满}}}()return rl
}func (rl *RateLimiter) Allow() bool {select {case <-rl.tokens:return truedefault:return false}
}
工作池模式
Channel结合goroutine可以轻松实现工作池模式:
func worker(id int, jobs <-chan Job, results chan<- Result) {for job := range jobs {result := process(job)results <- result}
}func main() {const numJobs = 100const numWorkers = 10jobs := make(chan Job, numJobs)results := make(chan Result, numJobs)// 启动工作者for w := 1; w <= numWorkers; w++ {go worker(w, jobs, results)}// 发送工作for j := 1; j <= numJobs; j++ {jobs <- Job{ID: j}}close(jobs)// 收集结果for a := 1; a <= numJobs; a++ {<-results}
}
相关文章:
深入解析Go语言Channel:源码剖析与并发读写机制
文章目录 Channel的内部结构Channel的创建过程有缓冲Channel的并发读写机制同时读写的可能性发送操作的实现接收操作的实现 并发读写的核心机制解析互斥锁保护环形缓冲区等待队列直接传递优化Goroutine调度 实例分析:有缓冲Channel的并发读写性能优化与最佳实践缓冲…...
C++中虚析构函数的作用是什么?为什么基类需要虚析构函数?
C中虚析构函数的作用是什么?为什么基类需要虚析构函数? 在C中,虚析构函数(virtual destructor)的作用是确保在通过基类指针或引用删除派生类对象时,能够正确调用派生类的析构函数,从而避免资源…...
ClickHouse合并任务与查询延迟专项测试
ClickHouse合并任务与查询延迟专项测试 1. 测试目的 验证周期性高延迟(~900ms)是否由后台合并任务(Merge)引起。 2. 测试环境 组件配置ClickHouse版本24.8.3.13服务器硬件8核CPU / 32GB内存 / NVMe SSD测试表log_test 3. 测试…...
3.14学习总结
今天完成了几道关于二叉树的算法题 关于二叉树的最小最大深度和数据流中的第k大元素,用到优先队列,学习了有关java的基础知识,学习了双指针法。...
OpenHarmony自定义子系统、部件与模块
如图所示,OpenHarmony系统源码中,大体上按照不同种类的功能分成多个子系统,然后一个子系统内部进一步在同类功能上的差异性划分成一个或多个部件,也就是说一个部件表示一个具体功能的源码集合。最后一个部件的源码再划分成一个或多…...
PPT 相关资料介绍
文章目录 一、iSlide 工具二、免费 PPT 模板下载三、Kimi 一键生成 PPT 一、iSlide 工具 iSlide 官网 二、免费 PPT 模板下载 7个完全免费的PPT模板下载网站 优品PPT 第一PPT 三、Kimi 一键生成 PPT ☆...
C# 发送邮件 报错:此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。
C# 发送邮件 报错:此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。 报错信息分析 当你遇到如下报错时: 此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。…...
大数据-spark3.5安装部署之standalone模式
真实工作中还是要将应用提交到集群中去执行,Standalone模式就是使用Spark自身节点运行的集群模式,体现了经典的master-slave模式。集群共三台机器,具体如下 u22server4spark: master worker u22server4spark2: worke…...
接口自动化入门 —— Jmeter实现在接口工具中关联接口处理方案
1. JMeter 接口关联处理的核心概念 接口关联是指在多个接口请求之间共享数据,例如将一个接口的返回值作为另一个接口的输入参数。常见的场景包括: 使用登录接口返回的 Token 作为后续接口的认证信息。 将一个接口返回的 ID 作为另一个接口的请求参数。…...
WebForms HTML:深入理解与高效运用
WebForms HTML:深入理解与高效运用 引言 随着互联网技术的飞速发展,WebForms HTML作为Web开发中的一种重要技术,已经成为了许多开发者日常工作中不可或缺的一部分。本文将深入探讨WebForms HTML的原理、应用场景以及高效运用技巧࿰…...
VSCode 搭建C++编程环境 2025新版图文安装教程(100%搭建成功,VSCode安装+C++环境搭建+运行测试+背景图设置)
名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、VScode下载及安装二、安装 MinGW-w64 工具链三、Windows环境变量配置四、检查 M…...
【Linux 内核 | 操作系统 | 内核编译】内核编译中与锁调试相关的设置有哪一些?内核 Debug 选项中 LockDep 和其他锁调试选项详解
问题描述: 我在看内核锁调试的信息时,看到了一些内核编译参数相关的设置,开启这些信息可以帮助我们在测试环境中调试锁的竞争情况,可以详细的打印出来一些线程持有锁,一些线程争抢锁的信息。 以下是我的配置&#…...
LinuX---Shell---变量
系统预定义变量 常用系统变量 PATH、HOME、PWD、SHELL、USER等 获取变量的值 语法:$变量名 $和变量名之间不能有空格。 案例实操 查看系统变量的值 fengubuntu:~$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/u…...
深入理解Spring MVC:构建灵活的Web应用
大家好!今天我们来聊聊Spring框架中的一个重要模块——Spring MVC。Spring MVC是一个基于MVC(Model-View-Controller)架构的Web框架,它提供了强大的功能来处理HTTP请求、生成动态内容以及管理Web应用程序的流程。无论是构建RESTfu…...
详解SQL数据查询功能
数据查询 一、 单表查询1. 选择表中的若干列2. 选择表中的若干元组3. ORDER BY 子句4. 聚合函数5. GROUP BY 子句6. LIMIT 子句综合示例: 二、 多表查询1. 等值连接查询 (Equi-Join)2. 非等值连接查询 (Non-Equi Join)3. 自然连接查询 (Natural Join)4. 复合条件连接…...
ArcGIS Pro 车牌分区数据处理与地图制作全攻略
在大数据时代,地理信息系统(GIS)技术在各个领域都有着广泛的应用,而 ArcGIS Pro 作为一款功能强大的 GIS 软件,为数据处理和地图制作提供了丰富的工具和便捷的操作流程。 车牌数据作为一种重要的地理空间数据…...
Git 本地常见快捷操作
Git 本地常见快捷操作 📌 1. 基本操作 操作命令初始化 Git 仓库git init查看 Git 状态git status添加所有文件到暂存区git add .添加指定文件git add <file>提交更改git commit -m "提交信息"修改最后一次提交信息git commit --amend -m "新…...
大视频背景暗黑风格的wordpress企业主题免费下载
整体风格是黑色的,首页首屏大视频背景,动态效果非常好。向下滚动时,滚动的特效也不错。 原文 https://www.bixugao.com/wp/26.html...
Apache Tomcat漏洞,对其进行升级
我们付出一些成本,时间的或者其他,最终总能收获一些什么。 升级背景: 近日,新华三盾山实验室监测到 Apache 官方修复了一个远程代码执行漏洞 (CVE-2025-24813) ,其CVSS3 漏洞评分为 7.5 。 影响范围 9.0.0.M1 ≤…...
fs的proxy_media模式失效
概述 freeswitch是一款简单好用的VOIP开源软交换平台。 在fs的使用过程中,某些场景只需要对rtp媒体做透传,又不需要任何处理。 在fs1.6的版本中,我们可以使用proxy_media来代理媒体的转发,媒体的协商由AB路端对端处理ÿ…...
Spring Boot与Apache Ignite集成:构建高性能分布式缓存和计算平台
1. 前言 1.1 什么是Apache Ignite Apache Ignite是一个高性能的分布式内存计算平台,支持内存缓存、分布式计算、流处理和机器学习等功能。它提供了低延迟的数据访问和强大的计算能力,适用于需要高性能和可扩展性的应用。 1.2 为什么选择Apache Ignite 高性能:Ignite利用内…...
深度学习优化-Gradient Checkpointing
数学原理参考: 梯度检查点技术(Gradient Checkpointing)详细介绍:中英双语-CSDN博客 视频讲解参考: 用梯度检查点来节省显存 gradient checkpointing_哔哩哔哩_bilibili Gradient Checkpointing(梯度检查…...
Linux内核实时机制19 - RT调度器3 - 实时任务出入队
Linux内核实时机制19 - RT调度器3 - 实时任务出入队 1、enqueue_task_rt和dequeue_task_rt都会调用dequeue_rt_stack接口, 当请求的rt_se对应的是任务组时,会从顶部到请求的rt_se将调度实体出列。 2、任务添加到rt运行队列时, 如果存在多个…...
CRM企业客户关系管理系统产品原型方案
客户关系管理系统(CRM)是企业产品应用中的典范,旨在通过信息技术和互联网技术提升企业核心竞争力,优化企业与顾客在销售、营销和服务方面的互动。本作品提供了一套通用型的CRM系统原型模板,涵盖数据管理、审批流程、统…...
HashMap ,HashTable , ConcurrentHashMap 面试
双列集合 HashMap 线程不安全的 HashMap 允许键和值为 null。不过要留意,HashMap 并非线程安全的,在多线程环境下使用可能会出现问题。 数组链表红黑树 jdk1.8 双列集合 存储keyvalue 底层数组的形式存在,初始值 为16 也可以在new HashMap…...
PyTorch 系列教程:探索自然语言处理应用
本文旨在介绍如何使用PyTorch进行自然语言处理(NLP)的基础知识,包括必要的库、概念以及实际代码示例。通过阅读本文,您将能够开始您的NLP之旅。 1. 理解PyTorch PyTorch是一个开源的机器学习库,基于Torch库࿰…...
【操作系统安全】任务2:用户与用户组
目录 一、用户与用户组介绍 1.1 用户 1.2 用户组 1.3 用户与用户组的关系 二、用户与用户组管理 2.1 用户管理 2.1.1 创建用户 2.1.2 设置用户密码 2.1.3 删除用户 2.2 用户组管理 2.2.1 创建用户组 2.2.2 删除用户组 2.2.3 将用户添加到用户组 三、影子账户创建…...
DeepSeek技术解析:MoE架构实现与代码实战
以下是一篇结合DeepSeek技术解析与代码示例的技术文章,重点展示其核心算法实现与落地应用: DeepSeek技术解析:MoE架构实现与代码实战 作为中国AI领域的创新代表,DeepSeek在混合专家模型(Mixture of Experts, MoE&…...
LLM对齐方法作用:主要解决大型语言模型(LLMs)输出与人类价值观、需求和安全规范不一致的问题
LLM对齐方法作用:主要解决大型语言模型(LLMs)输出与人类价值观、需求和安全规范不一致的问题 对齐方法(Alignment Methods) 主要解决大型语言模型(LLMs)输出与人类价值观、需求和安全规范不一致的问题。其核心目标是让模型生成的内容更符合人类预期,同时确保伦理合规性…...
【SpringMVC】常用注解:@RequestBody
1.作用 用于获取请求实体内容,直接使用得到的是keyvalue&keyvalue的数据。获取请求实体内容不适用get请求。 2.属性 required 描述是否有请求体,默认值为true。当取值为true时,get 请求方式会报错。如果取值为false,get请…...
brpc中的doublyBufferedData解析
double buffer解析(附brpc改进版) 双buffer是一个工程中常见的解决读写问题的结构。指的是读只读buff,写操作发生在写buff上。当写buff写完之后switch两个buff,然后写进程擦除原来的读数据,更新为最新的数据。 我们有…...
基于Android的记事本APP设计与实现:从需求分析到功能实现(超级简单记事本,附源码+文档报告)
基于Android的记事本APP设计与实现:从需求分析到功能实现 (以前大学课堂作业,抄在这里当个回忆吧) 引言 随着社会的不断进步,信息化建设不断发展,电子文字输入在生活、学习、工作中占有越来越重要的作用…...
Linux 部署 Spring Boot 项目, Web项目(2025版)
Linux 部署 Spring Boot 项目,Web项目(2025版) 一、简洁版1.1 Linux 环境配置1.2 将Spring Boot 项目部署到 Linux 中 二、详细版2.1 Linux 环境配置2.2 Spring Boot 项目搭建2.3 mysql 配置2.4 测试项目2.5 将Spring Boot 项目部署到 Linux …...
泛目录技术:智能缓存提升网站速度与稳定性
泛目录技术:智能缓存提升网站速度与稳定性 在现代网站运营中,速度和稳定性是用户体验和SEO优化的关键因素。2025奥顺互联推出的泛目录技术,通过智能缓存机制,为网站提供了卓越的性能提升和稳定性保障。本文将深入探讨该技术的特点…...
CNN SSP, ASPP, PPM 分割任务经典尺度聚合模块
SSP:Spatial Pyramid Pooling 让任意大小图像最终输出的特征维度始终固定,便于接全链接层。 4x4, 2x2,1x1区域的maxpooling,让任意大小图像最终输出最终特征维度始终为 (1641)*256 ASSP:Atrous Spatial Pyramid Pooling 不进行…...
Nping- Nmap中的一个工具-用于生成网络数据包并分析响应
Nping 工具介绍 Nping 是 Nmap 项目中的一个网络工具,用于生成网络数据包并分析响应。它可以用于网络探测、性能测试、防火墙测试、ARP 欺骗检测等多种场景。Nping 支持多种协议(如 TCP、UDP、ICMP、ARP),并允许用户自定义数据包…...
海马下载 1.0.2 | 纯净无广告,极简设计,不限速下载工具
海马下载是一款轻量级下载工具,仅保留核心链接下载功能,体积小巧仅21MB。实测无广告弹窗且不限速,适合追求简洁体验的用户。操作界面直观易用,可快速添加任务并查看下载进度。 大小:21M 下载地址: 百度网…...
【蓝桥杯—单片机】第十五届省赛真题代码题解析 | 思路整理
第十五届省赛真题代码题解析 前言赛题代码思路笔记竞赛板配置建立模板明确基本要求显示功能部分频率界面正常显示高位熄灭 参数界面基础写法:两个界面分开来写优化写法:两个界面合一起写 时间界面回显界面校准校准过程校准错误显示 DAC输出部分按键功能部…...
maven之自定义插件
写在前面 在使用maven肯定是离不开插件的,比如执行mvn clean或者时mvn compile其实运行的就是绑定的默认插件。虽然我们一般不需要来自定义插件,但是为了使用的过程中更加的清晰,来尝试自定义插件还是很有必要的,所以本文就一起来…...
Unity单例模式(c#泛型基类)
Unity单例模式 1 单例模式2 继承mono脚本单例模式基类3 SingletonAutoMono脚本 1 单例模式 单例模式基类模块 范型加约束,支持new来构造 //单例模式基类模块 //范型加约束,支持new来构造 public class BaseManager<T> where T :new() {private static T instance;public …...
java 中桥方法(Bridge Method)解决泛型和多态(即:类型兼容)而存在的
在 Java 中,**桥方法(Bridge Method)**是编译器自动生成的一种方法,主要用于解决泛型类型擦除和继承中的类型兼容性问题。以下是关于桥方法的几点关键信息: 1. 桥方法的作用 类型擦除兼容性:Java 的泛型在…...
Centos7阿里云yum源
#Step1:下载repository 没有wget命令 就用curl wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo #Step2:安装epel基础组件源 没有wget命…...
leetcode 102. 二叉树的层序遍历
方法一: 用两个数组进行迭代遍历 class Solution {public List<List<Integer>> levelOrder(TreeNode root) {if(root null) {return new ArrayList<List<Integer>>();}List<TreeNode> cur new ArrayList<TreeNode>();cur.a…...
Trae插件革命:用VSPlugin Helper实现VSCode市场插件全自动安装
之前有读者留言说trae都没有c的插件用,确实是这样,trae的插件源用的是open vsx,而c/c插件是vscode官方插件市场的,如果想直接在trae中安装c/c插件是不行的,只能先从vscode官方插件市场把vsix后缀文件先下载下来&#x…...
SpringCloud带你走进微服务的世界
认识微服务 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢? 单体架构 单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部…...
多线程(超详细) (ε≡٩(๑>₃<)۶ 一心向学)
多线程目录 一、认识线程 1、概念: 1) 线程是什么 2) 线程为什么存在 3) 进程与线程的区别 二、创建线程 1、方法1:继承Thread类 2、方法2:实现 Runnable 接口 3、方法3:匿名内部类创建 Thread 子类对象 4、方法4&#…...
LabVIEW旋转设备状态在线监测系统
为了提高大型旋转设备如电机和水泵的监控效率和故障诊断能力,用LabVIEW软件开发了一套实时监测与故障诊断系统。该系统集成了趋势分析、振动数据处理等多项功能,可实时分析电机电流、压力、温度及振动数据,以早期识别和预报故障。 项目背…...
RSS和TSS在网络流量处理中的优化作用
摘要 本文深入探讨了RSS(Receive Side Scaling)和TSS(Transmit Side Scaling)这两种网络流量处理技术的实现方法及其在网络性能优化中的重要作用。通过对硬件和软件实现方式的详细分析,阐述了它们如何在多队列网卡、多核处理器系统以及虚拟化环境中提升网络处理性能和吞吐…...
C++ 中的 RTTI(Run-Time Type Information,运行时类型识别)
我来为你详细讲解 C 中的 RTTI(Run-Time Type Information,运行时类型识别),并结合你提供的参考内容进行分析和说明。 什么是 RTTI? RTTI 是 C 提供的一种机制,允许程序在运行时识别对象的类型信息。它主要…...
Netty基础—4.NIO的使用简介二
大纲 1.Buffer缓冲区 2.Channel通道 3.BIO编程 4.伪异步IO编程 5.改造程序以支持长连接 6.NIO三大核心组件 7.NIO服务端的创建流程 8.NIO客户端的创建流程 9.NIO优点总结 10.NIO问题总结 4.伪异步IO编程 (1)BIO的主要问题 (2)BIO编程模型的改进 (3)伪异步IO编程 …...