百度后端开发一面

在这里插入图片描述

mutex, rwmutex

在Go语言中,Mutex(互斥锁)和RWMutex(读写锁)是用于管理并发访问共享资源的核心工具。以下是它们的常见问题、使用场景及最佳实践总结:


1. Mutex 与 RWMutex 的区别

  • Mutex:
    • 互斥锁,保证同一时刻只有一个 goroutine 访问共享资源。
    • 适用于读写操作都需要独占的场景(如计数器)。
  • RWMutex:
    • 读写锁,允许多个读操作并行,但写操作完全独占。
    • 适用于读多写少的场景(如配置信息读取)。

2. 常见问题及解决方案

2.1 死锁
  • 原因: 未释放锁、重复加锁或锁竞争导致永久阻塞。
  • 解决:
    • 使用 defer mu.Unlock() 确保释放锁。
    • 避免在同一个 goroutine 中重复加锁(不可重入)。
2.2 数据竞争
  • 原因: 未对共享资源的所有访问路径加锁。
  • 解决:
    • 明确锁的保护范围,确保所有访问共享数据的操作都被锁覆盖。
    • 使用 go test -race 检测数据竞争。
2.3 锁拷贝
  • 原因: 复制包含锁的结构体导致锁状态异常。
  • 解决:
    • 通过指针传递包含锁的结构体。
    • 避免直接复制 sync.Mutexsync.RWMutex
2.4 写饥饿(RWMutex)
  • 原因: 大量读操作阻塞写操作。
  • 解决:
    • 评估场景是否需要 RWMutex,或通过优先级队列优化写操作。
    • Go 1.18+ 的 Mutex 支持饥饿模式,避免长时间等待。

3. 使用场景

  • Mutex:
    var counter int
    var mu sync.Mutexfunc increment() {mu.Lock()defer mu.Unlock()counter++
    }
    
  • RWMutex:
    var config map[string]string
    var rwmu sync.RWMutexfunc readConfig(key string) string {rwmu.RLock()defer rwmu.RUnlock()return config[key]
    }func updateConfig(key, value string) {rwmu.Lock()defer rwmu.Unlock()config[key] = value
    }
    

4. 最佳实践

  1. 锁的作用域:
    • 锁应保护数据而非代码,确保所有访问共享资源的路径都被覆盖。
  2. 优先使用 defer:
    • 避免忘记解锁,尤其在复杂逻辑或异常处理中。
  3. 替代方案:
    • 对简单数值操作(如计数器)使用 atomic 包。
    • 通过 Channel 实现“通过通信共享内存”。
  4. 性能优化:
    • 减少锁的持有时间(如仅在读写共享数据时加锁)。
    • 在高并发场景中,评估锁竞争是否成为瓶颈。

5. 注意事项

  • 不可重入: Go 的锁不支持重入,同一 goroutine 重复加锁会导致死锁。
  • 零值可用: sync.Mutexsync.RWMutex 的零值可直接使用,无需初始化。
  • 避免嵌套锁: 多个锁的嵌套使用可能导致复杂死锁,需按固定顺序加锁。

通过合理选择 MutexRWMutex,并遵循最佳实践,可以有效避免并发问题,编写高效且安全的 Go 代码。

协程线程区别

协程(Coroutine)和线程(Thread)都是用于实现并发执行的机制,但它们在调度方式、资源消耗、通信机制等方面有显著区别。线程是操作系统级别的并发单位,由内核调度;而协程是用户态的轻量级线程,由程序自身调度。

  • 解答思路
  1. 首先明确两者的基本定义和使用场景。
  2. 对比它们的调度机制:线程由操作系统调度器管理,而协程由用户程序或运行时系统管理。
  3. 比较它们的开销:线程切换代价高,需要操作系统参与;协程切换快,仅需保存寄存器状态。
  4. 分析资源占用:线程拥有独立的栈空间,内存占用较大;协程共享线程资源,更节省内存。
  5. 总结适用场景:CPU密集型适合多线程,IO密集型或多任务协作适合协程。
  • 深度知识讲解

一、基本概念

  • 线程(Thread)
    线程是进程内的一个执行单元,多个线程共享同一进程的地址空间和资源。每个线程有自己独立的栈和寄存器上下文。线程由操作系统负责创建、销毁和调度。

  • 协程(Coroutine)
    协程是一种用户态的非抢占式多任务机制,可以看作是“轻量级线程”。它不像线程那样被操作系统调度,而是由程序员显式控制其切换。协程之间通常是协作式的,即当前协程主动让出控制权给下一个协程。

二、核心区别

  1. 调度机制不同
  • 线程是抢占式的,操作系统根据优先级、时间片等策略决定哪个线程运行。
  • 协程是协作式的,必须由当前协程主动 yield 控制权,才能切换到下一个协程。
  1. 上下文切换开销
  • 线程切换涉及内核态与用户态的切换,需要保存/恢复更多的寄存器和状态信息,开销大。
  • 协程切换完全在用户态进行,只需保存少量寄存器,开销极小。
  1. 资源占用
  • 线程通常默认分配较大的栈空间(如1MB),因此不能大量创建。
  • 协程栈空间较小(可配置为几KB),支持同时运行成千上万个协程。
  1. 同步与通信
  • 线程间通信需要互斥锁、信号量等机制,容易引发竞态条件。
  • 协程可以通过通道(channel)、事件循环等方式进行安全高效的通信。
  1. 并发模型
  • 多线程属于并行模型,适用于 CPU 密集型任务。
  • 协程属于异步/协作式并发模型,适用于 IO 密集型任务(如网络请求、文件读写)。

GMP调度

Go语言的GPM调度模型是Go运行时中用于处理并发的核心机制之一,它将Goroutine(轻量级线程)有效地映射到系统线程上,以最大化并发性能。GPM模型主要由三个部分组成:G(Goroutine)、P(Processor)、M(Machine)。让我们逐一详细介绍:

1. G(Goroutine)

  • Goroutine 是Go语言中用于并发执行的轻量级线程,每个Goroutine都有自己的栈和上下文信息。
  • Goroutine相对于操作系统的线程更加轻量级,可以在同一时间内运行成千上万的Goroutine。

2. P(Processor)

  • P 是处理Goroutine的调度器的上下文,每个P包含一个本地运行队列(Local Run Queue),用于存储需要运行的Goroutine。
  • P的数量由GOMAXPROCS设置决定,它决定了并行执行的最大线程数。
  • P不仅管理Goroutine,还负责与M协作,将Goroutine分配给M执行。

3. M(Machine)

  • M 代表操作系统的线程,负责执行Goroutine。一个M一次只能执行一个Goroutine。
  • M是实际执行代码的工作单元,M与P绑定后才能执行Goroutine。
  • M可以通过调度器从全局运行队列中拉取新的Goroutine,也可以与其他M协作完成工作。

4. GPM模型的调度过程

  • 调度器工作机制:Goroutine创建后会被放入P的本地队列,P会从该队列中选择Goroutine,并将其分配给M执行。如果本地队列为空,P可以从全局运行队列或其他P的队列中窃取任务。
  • 工作窃取机制:如果一个P的本地队列为空,而另一个P的本地队列中有多个Goroutine,前者可以从后者中窃取任务,从而保持系统的高效利用率。
  • 阻塞与调度:当M执行的Goroutine阻塞(例如I/O操作)时,M会释放当前的P并等待P重新分配任务,从而避免资源浪费。

5. 模型优点

  • 高效的并发调度:GPM模型使得Go语言可以高效地管理数百万个Goroutine的并发执行。
  • 可伸缩性:通过P与M的动态调度,GPM模型可以充分利用多核处理器的性能。
  • 轻量级:Goroutine非常轻量,创建和切换的成本比系统线程要低得多。

redis 常见数据类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

压缩列表

连续内存块组成的顺序型数据结构
在这里插入图片描述
在这里插入图片描述
O(1)定位首尾元素,其他需要遍历,不适合存储太多数据。
在这里插入图片描述
在这里插入图片描述

整数集合

在这里插入图片描述

跳表

跳表的优势是能支持平均O(logN)复杂度的节点查找
zset存储member和score
在这里插入图片描述
在这里插入图片描述

quicklist代替双向链表

在这里插入图片描述

在这里插入图片描述

listpack代替压缩列表

在这里插入图片描述
在这里插入图片描述

redis跳表的增删改查复杂度

O(logN)
在这里插入图片描述

redis跳表数据结构,高度创建,怎么删改

在这里插入图片描述
跳跃表(Skip List)的删除和修改操作需要结合其多层链表结构的特点进行调整,以下是具体实现步骤和原理:


一、删除操作

删除节点的核心步骤是:找到目标节点在所有层的引用,并更新这些层的指针以跳过该节点

1. 删除流程
  1. 查找目标节点

    • 从最高层开始,向右遍历,直到找到等于或大于目标值的节点。
    • 如果当前层的下一个节点等于目标值,记录该层的前驱节点(即指向目标节点的节点)。
    • 逐层向下重复此过程,直到最底层(Level 0)。
    • 时间复杂度:O(log n),与查找操作相同。
  2. 调整指针

    • 对每一层(从最高层到最底层):
      • 如果该层存在指向目标节点的前驱节点,将其指针指向目标节点的下一个节点。
      • 例如,若前驱节点在 Level 2 指向目标节点,则将前驱节点的 Level 2 指针指向目标节点的 Level 2 后继节点。
    • 操作示例
      原结构(删除节点 30):
      Level 2: 10 --------------------------> 50
      Level 1: 10 -------> 30 -------> 50
      Level 0: 10 -> 20 -> 30 -> 40 -> 50删除后:
      Level 2: 10 --------------------------> 50
      Level 1: 10 -------> 50
      Level 0: 10 -> 20 -> 40 -> 50
      
  3. 释放内存

    • 删除节点后,释放该节点的内存(在 Redis 等语言中可能由 GC 自动处理)。
2. 关键注意事项
  • 多线程安全:如果跳跃表支持并发操作,删除时需加锁(如 Redis 单线程模型无需考虑)。
  • 更新最大层高:若删除的节点是最高层的唯一节点,需降低跳跃表的最大层高。

二、修改操作

修改操作分为两种情况:仅修改值(Value)修改键(Score)

1. 仅修改值(Value)
  • 流程
    1. 查找目标节点:时间复杂度 O(log n)。
    2. 直接更新值:无需调整指针,直接修改节点的值字段。
  • 时间复杂度:O(log n)(仅查找时间)。
2. 修改键(Score)

由于跳跃表是按键(Score)有序排列的,修改键后需保证顺序性,因此需要先删除旧节点,再插入新节点

  • 流程

    1. 删除旧节点:O(log n)。
    2. 插入新节点:按新键值插入,O(log n)。
  • 总时间复杂度:O(log n) + O(log n) = O(log n).

  • 示例

    原结构(修改节点 30 的 Score 为 35):
    Level 1: 10 -------> 30 -------> 50
    Level 0: 10 -> 20 -> 30 -> 40 -> 50修改后:
    Level 1: 10 --------------------------> 50
    Level 0: 10 -> 20 -> 40 -> 50
    新插入节点 35:
    Level 1: 10 ----------> 35 -------> 50
    Level 0: 10 -> 20 -> 35 -> 40 -> 50
    

redis持久化AOF怎么做

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数组中重复的数据

https://leetcode.cn/problems/find-all-duplicates-in-an-array/description/

func findDuplicates(nums []int) []int {n := len(nums)ans := []int{}for i:=0;i<n;i++{x := nums[i]if x<0{x = -x}if nums[x-1]<0{ans = append(ans, x)}else{nums[x-1] = -nums[x-1]}}return ans
}

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

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

相关文章

STM32 IIC总线

目录 IIC协议简介 IIC总线系统结构 IIC总线物理层特点 IIC总线协议层 空闲状态 应答信号 数据的有效性 数据传输 STM32的IIC特性及架构 STM32的IIC结构体 0.96寸OLED显示屏 SSD1306框图及引脚定义 4针脚I2C接口模块原理图 字节传输-I2C 执行逻辑框图 命令表…

【unity游戏开发入门到精通——UGUI】整体控制一个UGUI面板的淡入淡出——CanvasGroup画布组组件的使用

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发——UGUI】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言CanvasGroup画布组组件参数 实战专栏推荐完结 前言 如果我们想要整体控制…

大型语言模型个性化助手实现

大型语言模型个性化助手实现 目录 大型语言模型个性化助手实现PERSONAMEM,以及用户资料和对话模拟管道7种原位用户查询类型关于大语言模型个性化能力评估的研究大型语言模型(LLMs)已经成为用户在各种任务中的个性化助手,从提供写作支持到提供量身定制的建议或咨询。随着时间…

生成式 AI 的未来

在人类文明的长河中,技术革命始终是推动社会跃迁的核心引擎。从蒸汽机解放双手,到电力点亮黑夜,再到互联网编织全球神经网络,每一次技术浪潮都在重塑人类的生产方式与认知边界。而今天,生成式人工智能(Generative AI)正以一种前所未有的姿态登上历史舞台——它不再局限于…

【序列化与反序列化详解】

文章目录 一、序列化与反序列化是什么&#xff1f;1. 为什么需要序列化&#xff1f;2. 反序列化的作用 二、常见的序列化格式三、不同编程语言的序列化与反序列化示例1. Python 的序列化与反序列化JSON 序列化Pickle 序列化&#xff08;仅限 Python&#xff09; 2. Java 的序列…

【单例模式】简介

目录 概念理解使用场景优缺点实现方式 概念理解 单例模式要保证一个类在整个系统运行期间&#xff0c;无论创建多少次该类的对象&#xff0c;始终只会有一个实例存在。就像操作系统中的任务管理器&#xff0c;无论何时何地调用它&#xff0c;都是同一个任务管理器在工作&#…

目标检测YOLO实战应用案例100讲- 无人机平台下露天目标检测与计数

目录 知识储备 基于YOLOv8改进的无人机露天目标检测与计数 一、环境配置与依赖安装 二、核心代码实现(带详细注释) 1. 改进YOLOv8模型定义(添加注意力机制) 2. 无人机视角数据增强(drone_augment.py ) 3. 多目标跟踪与计数(tracking_counter.py ) 4. 完整推理流…

【在Spring Boot中集成Redis】

在Spring Boot中集成Redis 依赖在application.yml中配置Redis服务地址创建Redis配置类缓存工具类使用 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency&…

计算机视觉——基于树莓派的YOLO11模型优化与实时目标检测、跟踪及计数的实践

概述 设想一下&#xff0c;你在多地拥有多个仓库&#xff0c;要同时监控每个仓库的实时状况&#xff0c;这对于时间和精力而言&#xff0c;都构成了一项艰巨挑战。从成本和可靠性的层面考量&#xff0c;大规模部署计算设备也并非可行之策。一方面&#xff0c;大量计算设备的购…

通信协议记录仪-产品规格书

以下是为 ​​通信协议记录仪(ProtoLogger Pro)​​ 的​​详细产品规格书​​,覆盖 ​​技术细节、场景需求、竞品差异化​​,确保可作为产品开发、市场营销及竞品分析的核心依据。 ​​通信协议记录仪产品规格书​​ ​​产品名称​​:ProtoLogger Pro(中文名称:蹲守…

python:sklearn 决策树(Decision Tree)

5. 决策树&#xff08;Decision Tree&#xff09; - 第5章 算法思想&#xff1a;基于信息增益&#xff08;ID3&#xff09;或基尼不纯度&#xff08;CART&#xff09;递归划分特征。 编写 test_dtree_1.py 如下 # -*- coding: utf-8 -*- """ 5. 决策树&…

【2-sat】2-sat算法内容及真题

A.2-sat简介 2-sat算法可以求解给定推出关系下的一种合法情况。题目中重常常&#xff0c;给定一些布尔变量A、B、C、D…&#xff0c;再给出一系列形如 B ⟶ A , C ⟶ D B \longrightarrow A , C \longrightarrow \neg D B⟶A,C⟶D的推出关系&#xff0c;询问使得所有推出关系…

【git】获取特定分支和所有分支

1 特定分支 1.1 克隆指定分支&#xff08;默认只下载该分支&#xff09; git clone -b <分支名> --single-branch <仓库URL> 示例&#xff08;克隆 某一个 分支&#xff09;&#xff1a; git clone -b xxxxxx --single-branch xxxxxxx -b &#xff1a;指定分支…

LWIP带freeRTOS系统移植笔记

以正点原子学习视频为基础的文章 LWIP带freeRTOS系统移植 准备资料/工程 1、lwIP例程1 lwIP裸机移植 工程 &#xff0c; 作为基础工程 改名为LWIP_freeRTOS_yizhi工程 2、lwIP例程6 lwIP_FreeRTOS移植 工程 3、freeRTO源码 打开https://www.freertos.org/网址下载…

组网技术知识点

1.port-isloate enable命令用于实现两个接口之间的二层数据隔离&#xff0c;三层数据互通。 2.交换机最多支持4096个VLAN&#xff0c;编号为1-4094 3.display bfd session all&#xff1a;查看BFD会话状态是否UP 4.RJ45通过双绞线连接以太网&#xff1b; AUI端口&#xff1…

Linux系统:进程程序替换以及相关exec接口

本节重点 理解进程替换的相关概念与原理掌握相关程序替换接口程序替换与进程创建的区别程序替换的注意事项 一、概念与原理 进程程序替换是操作系统中实现多任务和资源复用的关键机制&#xff0c;允许进程在运行时动态加载并执行新程序。 1.1 定义 进程程序替换是指用新程…

从此,K8S入门0门槛!

前言 当你想要入门K8S的时候&#xff0c;往往会被各种概念搞的晕乎乎的&#xff0c;什么API Server&#xff0c;Scheduler&#xff0c;Controller manager&#xff0c;Etcd&#xff0c;Pod&#xff0c;Kubelet&#xff0c;kube-proxy&#xff0c;deployment…… 哪怕你使用了…

[Python开发] 如何用 VSCode 编写和管理 Python 项目(从 PyCharm 转向)

在 Python 开发领域,PyCharm 一直是广受欢迎的 IDE,但其远程开发功能(如远程 SSH 调试)仅在付费版中提供。为了适应服务器部署需求,很多开发者开始将目光转向更加轻量、灵活且免费扩展能力强的 VSCode。本篇文章将详细介绍,从 PyCharm 转向 VSCode 后,如何高效搭建和管理…

处方流转平台权限控制模块设计(基于RBAC模型)

这是基于笔者的一些经验设计并加以完善的方案&#xff0c;仅供参考。 处方流转平台权限控制模块设计&#xff08;基于RBAC模型&#xff09; 1. 需求分析 处方流转平台需要严格的权限控制&#xff0c;确保&#xff1a; 患者隐私数据保护处方开具、审核、调配、发药等流程的合…

基于BM1684X+RK3588的智能工业视觉边缘计算盒子解决方案

智能工业视觉边缘计算终端技术方案书‌ ‌1. 产品概述‌ 1.1 产品定位 面向工业自动化场景的高性能AI视觉处理设备集成BM1684X&#xff08;8TOPS INT8&#xff09;AI加速芯片 RK3588&#xff08;6TOPS NPU&#xff09;异构计算支持工业级多相机接入、实时缺陷检测、高精度定…