NSOperation深入解析:从使用到底层原理
1. 基础概念与使用
1.1 NSOperation概述
NSOperation是Apple提供的一个面向对象的并发编程API,它基于GCD(Grand Central Dispatch)构建,但提供了更高层次的抽象和更丰富的功能。NSOperation允许开发者以面向对象的方式管理并发任务,提供了任务依赖、取消、暂停等高级特性。这种设计使得并发编程变得更加可控和可维护,特别适合处理复杂的异步任务场景。
1.1.1 与GCD的关系
NSOperation实际上是构建在GCD之上的高级抽象层,它使用GCD来执行底层的线程管理。在底层实现中,每个NSOperationQueue都会创建一个对应的GCD队列,通过这个队列来实际执行任务,同时NSOperation还维护了一个内部的dispatch_group来管理任务的完成状态。
// 伪代码:展示NSOperationQueue与GCD的关系
class NSOperationQueue {private let underlyingQueue: DispatchQueueprivate let group = DispatchGroup()private let semaphore: DispatchSemaphorefunc addOperation(_ operation: Operation) {// 创建GCD任务let block = {operation.start()}// 根据优先级选择队列let queue = queueForPriority(operation.queuePriority)// 提交到GCD队列queue.async(execute: block)}
}
1.1.2 核心优势
NSOperation的核心优势体现在以下几个方面:
- 任务依赖管理:通过有向无环图(DAG)实现精确的任务执行顺序控制
- 状态监控:通过KVO机制实现完整的状态追踪
- 取消机制:支持优雅的任务取消和资源清理
- 优先级管理:支持8级任务优先级
- 并发控制:提供精确的并发数量控制
1.2 基本使用
1.2.1 BlockOperation
BlockOperation是NSOperation的一个具体子类,它使用闭包(Block)来定义任务。这是最常用的NSOperation类型,特别适合Swift编程。
class DataProcessor {// 处理数据的方法func processData(_ data: String) {print("处理数据:\(data)")}// 执行任务的方法func executeTask() {// 1. 创建BlockOperationlet blockOperation = BlockOperation { [weak self] inguard let self = self else { return }self.processData("测试数据")}// 2. 添加额外的执行块blockOperation.addExecutionBlock { [weak self] inguard let self = self else { return }print("执行额外任务")}// 3. 设置完成回调blockOperation.completionBlock = {print("任务完成")}// 4. 创建队列并执行let queue = OperationQueue()queue.addOperation(blockOperation)}
}
1.2.2 InvocationOperation
InvocationOperation是NSOperation的另一个具体子类,它通过调用对象的方法来执行任务。这种方式更适合Objective-C编程。
class TaskProcessor: NSObject {// 处理任务数据的方法@objc func processTask(_ data: [String: Any]) -> Bool {print("处理任务数据:\(data)")return true}// 执行任务的方法func executeTask() {// 1. 创建处理器实例let processor = TaskProcessor()// 2. 准备任务数据let data: [String: Any] = ["key": "value", "count": 42]// 3. 创建InvocationOperationlet processOperation = NSInvocationOperation(target: processor,selector: #selector(processTask(_:)),object: data)// 4. 设置完成回调processOperation.completionBlock = {if let result = processOperation.result as? Bool, result {print("任务处理成功")} else {print("任务处理失败")}}// 5. 创建队列并执行let queue = OperationQueue()queue.addOperation(processOperation)}
}
1.3 高级特性
1.3.1 任务依赖
NSOperation支持设置任务之间的依赖关系,确保任务按特定顺序执行。依赖关系形成一个有向无环图,系统会自动根据依赖关系调度任务。
class TaskManager {func executeDependentTasks() {// 1. 创建任务let downloadOperation = BlockOperation {print("下载数据")}let parseOperation = BlockOperation {print("解析数据")}let saveOperation = BlockOperation {print("保存数据")}// 2. 设置依赖关系parseOperation.addDependency(downloadOperation)saveOperation.addDependency(parseOperation)// 3. 创建队列并添加任务let queue = OperationQueue()queue.addOperations([downloadOperation,parseOperation,saveOperation], waitUntilFinished: false)}
}
1.3.2 任务优先级
NSOperation支持设置任务优先级,影响任务的执行顺序。优先级从高到低依次为:.veryHigh、.high、.normal、.low、.veryLow。
class PriorityManager {func executePriorityTasks() {// 1. 创建不同优先级的任务let highPriorityOperation = BlockOperation {print("高优先级任务")}highPriorityOperation.queuePriority = .highlet normalPriorityOperation = BlockOperation {print("普通优先级任务")}normalPriorityOperation.queuePriority = .normallet lowPriorityOperation = BlockOperation {print("低优先级任务")}lowPriorityOperation.queuePriority = .low// 2. 创建队列并添加任务let queue = OperationQueue()queue.addOperation(lowPriorityOperation)queue.addOperation(normalPriorityOperation)queue.addOperation(highPriorityOperation)}
}
1.3.3 任务取消
NSOperation支持取消任务,可以优雅地停止任务执行。取消操作会递归地取消所有依赖任务,并确保资源能够被正确释放。
class CancellationManager {func executeCancellableTask() {// 1. 创建可取消的任务let operation = BlockOperation {// 定期检查是否被取消for i in 1...10 {if operation.isCancelled {print("任务被取消")return}print("执行任务 \(i)")Thread.sleep(forTimeInterval: 0.5)}}// 2. 设置完成回调operation.completionBlock = {if operation.isCancelled {print("任务已取消,清理资源")} else {print("任务正常完成")}}// 3. 创建队列并添加任务let queue = OperationQueue()queue.addOperation(operation)// 4. 延迟取消任务DispatchQueue.main.asyncAfter(deadline: .now() + 2) {operation.cancel()}}
}
1.3.4 并发控制
NSOperationQueue支持控制并发数量,避免创建过多线程。可以通过设置maxConcurrentOperationCount来控制并发数。
class ConcurrencyManager {func executeConcurrentTasks() {// 1. 创建队列并设置并发数let queue = OperationQueue()queue.maxConcurrentOperationCount = 2// 2. 添加多个任务for i in 1...5 {queue.addOperation {print("任务\(i)开始")Thread.sleep(forTimeInterval: 1)print("任务\(i)结束")}}// 3. 等待所有任务完成queue.waitUntilAllOperationsAreFinished()}
}
2. 底层实现原理
2.1 生命周期管理
NSOperation对象在其生命周期中会经历ready、executing、finished和cancelled四个状态,这些状态通过KVO机制进行通知。状态转换遵循特定的规则:
- 任务从ready状态开始
- 可以转换到executing或cancelled状态
- executing状态可以转换到finished状态
- cancelled状态也可以转换到finished状态
- finished状态是最终状态,不能转换到其他状态
// 伪代码:展示Operation状态管理的简化实现
enum OperationState {case readycase executingcase finishedcase cancelled
}class Operation {private var state: OperationState = .readyprivate let stateLock = NSLock()func start() {stateLock.lock()defer { stateLock.unlock() }if state == .cancelled {state = .finishedreturn}state = .executingmain()state = .finished}func cancel() {stateLock.lock()defer { stateLock.unlock() }if state != .finished {state = .cancelled// 取消所有依赖任务for dependent in dependents {dependent.cancel()}}}
}
代码说明:
- 使用枚举定义Operation的四种状态,确保状态值的类型安全
- 使用NSLock保证状态转换的线程安全
- 在start()方法中实现状态转换逻辑,确保状态转换的原子性
- 在cancel()方法中实现取消逻辑,包括递归取消依赖任务
- 使用defer确保锁一定会被释放,避免死锁
2.2 线程管理
NSOperationQueue内部使用GCD来管理线程,它维护了一个底层的GCD队列和相关的信号量。通过这个队列来实际执行任务,同时使用信号量来控制并发数量,通过dispatch_group来管理任务的完成状态。
2.2.1 底层队列实现
NSOperationQueue的底层实现主要依赖于GCD,这种设计带来了以下优势:
-
高效的任务调度:
- 利用GCD的高效线程池管理
- 自动的负载均衡
- 系统级的线程优化
-
灵活的队列配置:
- 支持自定义底层GCD队列
- 可以设置队列的QoS级别
- 支持串行和并发队列
// 伪代码:展示NSOperationQueue的底层队列实现
class NSOperationQueue {private let underlyingQueue: DispatchQueueprivate let group = DispatchGroup()private let semaphore: DispatchSemaphoreprivate let lock = NSLock()private var operations: [Operation] = []init() {// 创建底层GCD队列underlyingQueue = DispatchQueue(label: "com.app.operationQueue",qos: .default,attributes: .concurrent)semaphore = DispatchSemaphore(value: maxConcurrentOperationCount)}// 设置底层GCD队列func setUnderlyingQueue(_ queue: DispatchQueue?) {lock.lock()defer { lock.unlock() }underlyingQueue = queue ?? DispatchQueue.global()}// 添加Operation到队列func addOperation(_ operation: Operation) {lock.lock()operations.append(operation)lock.unlock()// 将Operation转换为GCD任务let block = { [weak self] inself?.semaphore.wait()operation.start()self?.semaphore.signal()}// 提交到GCD队列underlyingQueue.async(execute: block)}// 等待所有任务完成func waitUntilAllOperationsAreFinished() {group.wait()}
}
代码说明:
- 使用DispatchQueue作为底层队列,支持并发执行
- 使用DispatchGroup管理任务的完成状态
- 使用DispatchSemaphore控制并发数量
- 使用NSLock保护operations数组的线程安全
- 支持自定义底层GCD队列
- 提供等待所有任务完成的机制
2.2.2 任务调度机制
NSOperationQueue的任务调度机制主要包括以下几个方面:
-
任务提交:
- 将Operation转换为GCD任务
- 根据优先级选择合适的QoS级别
- 通过信号量控制并发数量
-
执行控制:
- 支持暂停和恢复队列
- 可以取消单个或所有任务
- 提供任务完成回调
-
资源管理:
- 动态调整线程数量
- 避免线程爆炸
- 优化系统资源使用
// 伪代码:展示任务调度机制的实现
extension NSOperationQueue {// 暂停队列func suspend() {underlyingQueue.suspend()}// 恢复队列func resume() {underlyingQueue.resume()}// 取消所有任务func cancelAllOperations() {lock.lock()defer { lock.unlock() }for operation in operations {operation.cancel()}}// 设置任务优先级func setOperationPriority(_ priority: Operation.QueuePriority, for operation: Operation) {lock.lock()defer { lock.unlock() }operation.queuePriority = priority// 重新调度任务rescheduleOperation(operation)}private func rescheduleOperation(_ operation: Operation) {// 实现任务重新调度的逻辑}
}
代码说明:
- 提供队列的暂停和恢复功能
- 支持批量取消任务
- 允许动态调整任务优先级
- 实现任务重新调度机制
2.3 依赖管理
NSOperation的依赖管理通过有向无环图实现,它维护了依赖集合和依赖者集合,通过锁机制保证线程安全,同时使用信号量来控制并发访问。
// 伪代码:展示Operation依赖管理的简化实现
class Operation {private let dependencySemaphore = DispatchSemaphore(value: 1)private var dependencies: Set<Operation> = []private var dependents: Set<Operation> = []private let lock = NSLock()func addDependency(_ operation: Operation) {lock.lock()dependencies.insert(operation)operation.dependents.insert(self)lock.unlock()updateReadyState()}private func updateReadyState() {let isReady = dependencies.allSatisfy { $0.isFinished }setState(isReady ? .ready : .pending)}private func setState(_ newState: OperationState) {willChangeValue(forKey: "state")state = newStatedidChangeValue(forKey: "state")}
}
代码说明:
- 使用Set存储依赖和依赖者,确保唯一性
- 使用信号量控制依赖关系的并发访问
- 使用NSLock保护依赖集合的线程安全
- 通过KVO机制通知状态变化
- 在添加依赖时自动更新就绪状态
2.4 取消机制
NSOperation的取消机制通过状态管理和依赖传播实现。当任务被取消时,它会更新自己的状态,同时递归地取消所有依赖任务,确保资源能够被正确释放。
// 伪代码:展示Operation取消机制的简化实现
class Operation {private var isCancelled: Bool = falseprivate let lock = NSLock()func cancel() {lock.lock()if !isCancelled {isCancelled = true// 取消所有依赖任务for dependent in dependents {dependent.cancel()}// 清理资源cleanup()}lock.unlock()}private func cleanup() {// 实现资源清理逻辑}var isCancelled: Bool {lock.lock()defer { lock.unlock() }return isCancelled}
}
代码说明:
- 使用布尔值标记取消状态
- 使用NSLock保护取消状态的线程安全
- 实现递归取消依赖任务的逻辑
- 提供资源清理的扩展点
- 使用defer确保锁一定会被释放
2.5 性能优化
2.5.1 避免线程爆炸
NSOperationQueue提供了默认的并发数量限制,同时也支持根据系统处理器数量动态调整并发数量。
class OptimizedQueue {private let queue: OperationQueue = {let queue = OperationQueue()// 使用默认并发数queue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount// 或者根据处理器数量设置queue.maxConcurrentOperationCount = ProcessInfo.processInfo.processorCountreturn queue}()
}
代码说明:
- 使用默认并发数或处理器数量作为并发限制
- 通过属性初始化器配置队列
- 避免创建过多线程导致的资源浪费
2.5.2 内存管理
NSOperation的内存管理需要注意循环引用和资源释放,使用weak引用避免循环引用,使用autoreleasepool管理临时对象。
class MemorySafeOperation {// 创建Operation时直接使用weak selflet operation = BlockOperation { [weak self] inautoreleasepool {guard let self = self else { return }// 处理大量临时对象var temporaryData: [Data] = []for i in 0..<1000 {// 创建临时数据let data = Data(count: 1024 * 1024) // 1MBtemporaryData.append(data)// 处理数据self.processData(data)// 每处理100个对象清理一次if i % 100 == 0 {temporaryData.removeAll()}}}}
}
代码说明:
- 在BlockOperation的闭包中直接使用[weak self]避免循环引用
- 使用autoreleasepool管理大量临时对象的创建和释放
- 定期清理临时数据,避免内存占用过高
- 在completionBlock中清理临时文件
- 使用guard let确保self存在
- 确保资源能够及时释放
2.5.3 性能监控
NSOperationQueue提供了性能监控功能,可以追踪任务的执行时间、平均执行时间、总执行时间和每秒执行的任务数量。
// 伪代码:展示性能监控的简化实现
extension OperationQueue {private var startTime: CFTimeInterval = 0private var operationCount: Int = 0private var totalExecutionTime: CFTimeInterval = 0func startPerformanceMonitoring() {startTime = CFAbsoluteTimeGetCurrent()operationCount = 0totalExecutionTime = 0}func operationDidFinish(_ operation: Operation) {let executionTime = CFAbsoluteTimeGetCurrent() - operation.startTimetotalExecutionTime += executionTimeoperationCount += 1let averageTime = totalExecutionTime / Double(operationCount)let totalTime = CFAbsoluteTimeGetCurrent() - startTimeprint("""Performance Report:Total Operations: \(operationCount)Average Time: \(averageTime * 1000) msTotal Time: \(totalTime * 1000) msOperations/Second: \(Double(operationCount) / totalTime)""")}
}
代码说明:
- 使用CFTimeInterval记录精确的时间
- 计算关键性能指标
- 提供性能报告输出
- 支持实时监控和统计
2.6 底层实现总结
NSOperation的底层实现是一个复杂的系统,它通过多个关键机制协同工作:
-
状态管理:
NSOperation通过状态机管理Operation的生命周期,使用KVO机制通知状态变化,并通过锁机制确保状态转换的原子性和线程安全。 -
线程管理:
NSOperationQueue基于GCD实现高效的线程调度,使用信号量控制并发数量,并通过dispatch_group管理任务的完成状态。 -
依赖管理:
NSOperation使用有向无环图管理任务依赖,通过锁机制保证线程安全,并自动处理依赖关系的状态更新。 -
取消机制:
NSOperation支持优雅的任务取消,递归处理依赖任务的取消,并确保资源的正确释放。 -
性能优化:
NSOperationQueue通过智能的并发控制、内存安全的管理机制和完善的性能监控系统,实现了高效的资源利用。
这些机制共同构成了一个强大而灵活的并发编程框架,使得NSOperation能够满足各种复杂的并发编程需求。
3. 总结与展望
NSOperation作为iOS并发编程的重要框架,其价值不仅体现在其强大的功能特性上,更在于它为我们提供了一个理解并发编程的绝佳范例。通过其面向对象的设计理念,NSOperation将复杂的并发概念封装成易于理解和使用的API,使得开发者能够以更直观的方式处理并发任务。其基于GCD的底层实现,既保证了性能,又提供了更高层次的抽象,这种设计思路对现代并发编程框架的开发具有重要的参考价值。
在实际开发中,选择使用NSOperation还是GCD需要根据具体场景来决定。NSOperation特别适合需要复杂任务管理的场景,比如需要精确控制任务执行顺序、管理任务生命周期、实现优雅的任务取消机制等。而GCD则更适合处理简单的异步任务,特别是在性能要求极高或不需要复杂任务管理的场景下。在使用NSOperation时,开发者需要注意内存管理、线程安全和性能优化等问题,通过合理使用weak self、锁机制和并发控制来避免常见陷阱。
随着Swift语言的不断发展,特别是async/await和结构化并发的引入,并发编程正在经历一场革命性的变革。然而,NSOperation所体现的设计理念和最佳实践仍然具有重要的指导意义。它教会我们如何优雅地处理任务依赖、如何实现可靠的状态管理、如何设计可扩展的并发系统。这些经验对于理解和应用新的并发模型都大有裨益。在未来,我们可能会看到NSOperation与新的并发特性进行更深层次的融合,但其核心思想将继续影响并发编程的发展方向。
如果觉得本文对你有帮助,欢迎点赞、收藏、关注我,后续会持续分享更多 iOS 底层原理与实战经验
相关文章:
NSOperation深入解析:从使用到底层原理
1. 基础概念与使用 1.1 NSOperation概述 NSOperation是Apple提供的一个面向对象的并发编程API,它基于GCD(Grand Central Dispatch)构建,但提供了更高层次的抽象和更丰富的功能。NSOperation允许开发者以面向对象的方式管理并发任…...
suna工具调用可视化界面实现原理分析(二)
这是一个基于React的浏览器操作可视化调试组件,主要用于在AI开发工具中展示网页自动化操作过程(如导航、点击、表单填写等)的执行状态和结果。以下是关键技术组件和功能亮点的解析: 一、核心功能模块 浏览器操作状态可视化 • 实时…...
【大模型面试每日一题】Day 9:BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别?
【大模型面试每日一题】Day 9:BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别? 📌 题目重现 🌟 面试官:预训练任务中,BERT 的 MLM(Masked Language Modeling)和 GPT 的 …...
分析strtol(),strtoul()和strtod()三个函数的功能
字符串转换为数值部分和子字符串首地址的函数有strtol(),strtoul()和strtod()三个函数。 1、strtol()函数 long int strtol(const char *str, char **endptr, int base) //当base0时,若字符串不是以"0","0x"和"0X"开头,则将数字部分按照10进制…...
Spring Boot 加载application.properties或application.yml配置文件的位置顺序。
我换一种更通俗易懂的方式,结合具体例子来解释 Spring Boot 加载application.properties或application.yml配置文件的位置顺序。 生活场景类比 想象你要找一本书,你有几个可能存放这本书的地方,你会按照一定顺序去这些地方找,直…...
C++进阶之——多态
1. 多态的概念 多态是用来描述这个世界的 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态。 这里就很厉害了,能够实现特殊处理,本文章就是来仔细…...
第13项三期,入组1123例:默沙东启动TROP2 ADC+PD-1子宫内膜癌头对头临床
Umabs DB作为目前全球最全面的抗体药物专业数据库,收录全球近10000个从临床前到商业化阶段抗体药物,涉及靶点1600,涉及疾病种类2400,研发机构2900,覆盖药物蛋白序列、专利和临床等多种专业信息。Umabs DB药物数据库已正…...
政务服务智能化改造方案和案例分析
政务服务智能化改造方案和案例分析 一、引言 在数字化时代浪潮的推动下,政务服务智能化改造已成为提升政府服务效能、优化营商环境、增强民众满意度的关键举措。传统政务服务模式存在流程繁琐、信息孤岛、办理效率低等问题,难以满足现代社会快节奏发展和…...
15.日志分析入门
日志分析入门 第一部分:日志分析基础第二部分:日志分析方法与工具第三部分:日志分析实践总结 目标: • 理解日志分析在网络安全中的作用 • 掌握日志的基本类型和分析方法 • 通过实践初步体验日志分析的过程 第一部分ÿ…...
EPSG:3857 和 EPSG:4326 的区别
EPSG:3857 和 EPSG:4326 是两种常用的空间参考系统,主要区别在于坐标表示方式和应用场景。以下是它们的核心差异: 1. 坐标系类型 EPSG:4326(WGS84) 地理坐标系(Geographic Coordinate System),基…...
Python Cookbook-7.2 使用 pickle 和 cPickle 模块序列化数据
任务 你想以某种可以接受的速度序列化和重建Python 数据结构,这些数据既包括基本Python 对象也包括类和实例。 解决方案 如果你不想假设你的数据完全由基本 Python 对象组成,或者需要在不同的 Python 版本之间移植,再或者需要将序列化后的…...
Java学习手册:Spring 多数据源配置与管理
在实际开发中,有时需要连接多个数据库,例如,一个系统可能需要从不同的数据库中读取和写入数据。Spring 提供了多种方式来配置和管理多数据源,以下将介绍常见的配置和管理方法。 一、多数据源配置 在 Spring 中,可以通…...
六、shell脚本--正则表达式:玩转文本匹配的“万能钥匙”
想象一下,你需要在一大堆文本(比如日志文件、配置文件、网页代码)里查找符合某种特定模式的字符串,而不是仅仅查找固定的单词。比如说: 找出所有的电子邮件地址 📧。找到所有看起来像电话号码 Ὅ…...
Gradio全解20——Streaming:流式传输的多媒体应用(4)——基于Groq的带自动语音检测功能的多模态Gradio应用
Gradio全解20——Streaming:流式传输的多媒体应用(4)——基于Groq的带自动语音检测功能的多模态Gradio应用 本篇摘要20. Streaming:流式传输的多媒体应用20.4 基于Groq的带自动语音检测功能的多模态Gradio应用20.4.1 组件及配置1.…...
力扣hot100 (除自身以外数组的乘积)
238. 除自身以外数组的乘积 中等 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除…...
LFU算法解析
文章目录 LFU缓存中关键变量的访问与更新机制1. min_freq - 最小频率访问时机更新时机更新示例 2. capacity - 缓存容量访问时机更新时机访问示例 3. key_to_node - 键到节点的映射访问时机更新时机更新示例 4. freq_to_dummy - 频率到链表哑节点的映射访问时机更新时机更新示例…...
RHCSA笔记2
RHCSA基础命令 (一)命令格式 (1)命令名【选项】【参数】 选项:决定命令执行的方式,通常有个-或--开头 参数:决定命令作用的目标(目录,文件,磁盘ÿ…...
JavaSE核心知识点01基础语法01-02(基本数据类型、运算符、运算符优先级)
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 JavaSE核心知识点01基础语法01-02࿰…...
FOC算法开环控制基础
1. 为什么要有FOC算法 先看看从有刷电机到无刷电机的简单介绍,如下图1,通电螺线圈会产生磁场,这个磁场会产生N级和S级,然后这个电磁铁就可以吸引永磁体,S级吸引N级,N级吸引S级,通俗的来说&…...
进程间通信——管道
概念 进程间通信(Inter-Process Communication,简称 IPC)是指在不同进程之间进行数据交换和信息传递的机制。它的目的主要有4种: 数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间…...
五一作业-day02
文章目录 1. 每日基操2. 模拟故障2.1 **remove regular empty file 是否删除普通文件(空的)?**2.2 **is a directory xxx是一个目录**2.3 **xxx not a directory 不是一个目录**2.4 Cant open file for writing2.5 **No write since last change** 3. 习题4. **进阶习题** 1. …...
Springclound常用五大组件及其使用原理
注册中心Eureka Eureka-Server:就是服务注册中心(可以是一个集群),对外暴露自己的地址。 提供者:启动后向Eureka注册自己信息(地址,服务名称等),并且定期进行服务续约 …...
Qt 显示QRegExp 和 QtXml 不存在问题
QRegExp 和 QtXml 问题 在Qt6 中 已被弃用; 1)QRegExp 已被弃用,改用 QRegularExpression Qt5 → Qt6 重大变更:QRegExp 被移到了 Qt5Compat 模块,默认不在 Qt6 核心模块中。 错误类型解决方法QRegExp 找不到改用 Q…...
开元类双端互动组件部署实战全流程教程(第4部分:后台配置系统与参数动态控制)
作者:曾经因为后台配置写错,导致全服进不去房的工程师 组件附带的后台管理系统为 PHP 编写,界面简洁但功能齐全。具备完整的模块划分与权限体系,支持动态参数下发、日志审计、行为数据统计等。 七、前端后台交互流程图与代码示例 …...
MySQL基础关键_008_DDL 和 DML(一)
目 录 一、DDL 1.创建表 (1)语法格式 (2)实例 2.查看建表语句 (1)语法格式 (2)实例 3.修改表名 (1)语法格式 (2)实例 4.新…...
基于SpringBoot + Vue 的火车票订票系统
包含: [1]源码✔ 数据库文件✔ [2]万字文档✔ [3]视频与图文配置教程✔ 功能描述: 本系统包含管理员、用户两个角色。 管理员:用户管理、新闻公告管理、车辆管理、车站及路线管理、留言建议管理、车次信息管理 用户:购票操作、查…...
飞致云开源社区月度动态报告(2025年4月)
自2023年6月起,中国领先的开源软件公司飞致云以月度为单位发布《飞致云开源社区月度动态报告》,旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况,以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源运营数据概览&…...
解决跨域的4种方法
00_跨域的概念 浏览器只允许请问具有相同的协议,域名,端口,进行请求,有一个不同,就会拒绝。 01.前后端协商jsonp //jsonp//jsonp 是 json with padding 的缩写,是一种通过 <script> 标签的 src 属性…...
C# 方法(局部函数和参数)
本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 局部函数 正如刚刚所解释的&…...
kotlin 02flow-sharedFlow 完整教程
一 sharedFlow是什么 SharedFlow 是 Kotlin 协程中 Flow 的一种 热流(Hot Flow),用于在多个订阅者之间 共享事件或数据流。它适合处理 一次性事件(如导航、弹窗、Toast、刷新通知等),而不是持续状态。 ✅ …...
数据库原理——E-R图的极速省流理解 例题解析
前言 数据库一节没听,一个小时看书给我大致看懂了 E-R概念模型极速省流版 E-R图的重点: 关系图,三要素——实体、属性、联系 图形标识——矩形、椭圆形、菱形 1.实体和属性也可以放一个框矩形框 2.菱形两层边:弱实体集的联…...
5.4 - 5.5Web基础+c语言拓展功能函数
StringBoot HTTP协议: 规定了浏览器与服务器之间数据传递的规则。 请求协议: 请求数据格式: 请求头和请求体之间有一个空行隔开 响应协议: 响应数据格式: 响应头和响应体之间存在空行隔开。 响应数据设置࿱…...
Java抽象类与接口详解
一、抽象类(Abstract Class) 1. 定义与基本使用 // 抽象类定义 public abstract class Animal {// 抽象方法(无实现)public abstract void makeSound();// 具体方法(有实现)public void sleep() {System.out.println("动物在睡觉");} }// 继承抽象类 class Dog ext…...
网络延时 第四次CCF-CSP计算机软件能力认证
就是求树的直径: 思路:函数代表当前根节点的最长距离 然后遍历保存当前树的所有孩子的最长距离 和次长距离 如果是叶子节点就返回0 在每次获得每个节点的次长距离和最长距离就更新全局直径 最后获得最长距离 Ac代码: #include <bits/stdc.h> using namespa…...
【C++进阶十】多态深度剖析
【C进阶十】多态深度剖析 1.多态的概念及条件2.虚函数的重写3.重写、重定义、重载区别4.C11新增的override 和final5.抽象类6.虚表指针和虚表6.1什么是虚表指针6.2指向谁调用谁,传父类调用父类,传子类调用子类 7.多态的原理8.单继承的虚表状态9.多继承的…...
网络传输中字节序
在小端字节序主机发送数据 0x1234 的情况下,(单字节没有字节序)我们可以分步骤来分析接收端如何解析这个数据: 1. 小端字节序主机的存储方式 在小端字节序中,低地址存储低字节,高地址存储高字节。 数据 0x1234 的字节表示为: 低字节:0x34 高字节:0x12 因此,在小端字…...
前端- ElementPlus入门
1.介绍 Element:是饿了么公司前端开发团队提供的一套基于 Vue3 的网站组件库,用于快速构建网页。 Element 提供了很多组件供我们使用。例如 超链接、按钮、图片、表格等等。 官方网站:一个 Vue 3 UI 框架 | Element Plus 2.步骤 1.安装E…...
AI Agent 要用到的技术
AI 发展是大趋势,以下是目前要用到的一些技术项 不论你从事哪个方向,这个技术栈都有必要学习 LangChainTransformersMicrosoft Semantic KernelLangflowLangGrphLangSmith 学习网站 以下是 LangChain、Transformers、Microsoft Semantic Kernel 的学习…...
# 从零构建一个简单的卷积神经网络:手写数字识别
从零构建一个简单的卷积神经网络:手写数字识别 在深度学习的世界里,卷积神经网络(CNN)是处理图像数据的强大工具。今天,我们将通过一个简单的例子,从零开始构建一个CNN模型,用于手写数字识别。…...
【RK3588嵌入式图形编程】-Cairo-Cairo图形库支持后端
Cairo图形库支持后端 文章目录 Cairo图形库支持后端1、PNG图像后端2、PDF文件后端3、SVG文件后端4、GTK窗口支持Cairo库支持多种后端。在本文中,我们使用Cairo创建PNG图像、PDF文件、SVG文件,并在GTK窗口上绘制。 1、PNG图像后端 在第一个示例中,我们创建一个 PNG 图像。 …...
LCD,LED
本文来源 : 腾讯元宝 LCD(Liquid Crystal Display)液晶显示器 LCD本身并不能发光,而是控制光的传输。 LCD内充满了棒状的液态分子(液晶),这些分子可以形成扭转的螺旋线,弯曲来自显示器背后光源产生的光线或…...
HTML 元素
什么是 HTML 元素? HTML 元素(Element)是构成 HTML 文档的基本单位,它由开始标签、内容和结束标签组成,用于定义网页的结构和内容。元素是 HTML 标记语言的核心概念,每个元素都有特定的语义和用途。 元素…...
(undone) MIT6.S081 2023 学习笔记 (Day11: LAB10 mmap)
url: https://pdos.csail.mit.edu/6.1810/2023/labs/mmap.html 任务0:讲义如下 (完成) mmap和munmap系统调用允许UNIX程序对其地址空间进行精细控制。它们可用于进程间共享内存、将文件映射到进程地址空间,并作为用户级页面错误处理方案的一部分&#x…...
7400MB/s5050TBW完美结合,全新希捷酷玩530R SSD体验评测
7400MB/s&5050TBW完美结合,全新希捷酷玩530R SSD体验评测 哈喽小伙伴们好,我是Stark-C~ 说到希捷酷玩530 SSD,很多硬核进阶玩家应该都知道,或者说正在使用(比如说我~)。 作为希捷大厂旗下高性能SSD的…...
【数据结构与算法】同余计算 哈希表与前缀和问题特征和模板化思路
加减乘负的类同余计算 加乘模情况 两数和模 : (a b) mod m (a mod m b mod m) mod m乘积模 : (a * b) mod m ((a mod m) * (b mod m)) mod m 加模证明如下 : a q1 * m r1 , b q2 * m r2则 a mod m r1 , b mod m r2(a b) mod m ((q1 q2) * m (r1 r2)) mod m …...
TS 交叉类型
很类似于接口继承啊 哈哈哈 使用type关键字声明交叉类型 // 声明交叉类型 type PersonDetail person & Contactlet theshy:PersonDetail { name:the shy,phone:马头 }交叉类型和接口实现对对象的类型注解的区别与联系 如果在接口继承时发生同名属性冲突会报不兼容的错…...
FreeRTOS学习系列·二值信号量
目录 1. 信号量的基本概念 2. 二值信号量 3. 应用场景 4. 运作机制 5. 信号量控制块 6. 常用信号量函数接口API 6.1 创建二值信号量 xSemaphoreCreateBinary() 6.2 信号量删除函数 vSemaphoreDelete() 6.3 信号量释放函数 6.3.1 xSemaphoreGive() 6.3.2 …...
二叉搜索树 AVL树 红黑树 的性质
二叉搜索树 如何判断一棵树是否是二叉搜索树? 1.方法一 左子树的所有节点值 < 当前节点值,右子树的所有节点值 > 当前节点值,左右子树也必须满足 。 2.方法二 中序遍历,得到的序列是有序的 红黑树 红黑树的性质 1.根…...
分析 Docker 磁盘占用
以下是分析 Docker 磁盘占用的详细步骤和工具指南,帮助开发者快速定位和清理冗余数据: 1. 查看 Docker 磁盘使用概览 docker system df 输出说明: TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 15 …...
LLM提示词设计及多轮对话优化策略在心理健康咨询场景中的应用研究
多轮对话策略:设计LLM提示词并优化多轮对话输出 LLM提示词设计及多轮对话优化策略在心理健康咨询场景中的应用研究 摘要 本文针对大语言模型(LLM)在心理健康问题咨询对话场景中的应用,系统研究提示词设计方法及多轮对话优化策略。通过分析提示词核心原理,构建包含任务指…...