当前位置: 首页 > news >正文

iOS RunLoop 深入解析

本文深入探讨 iOS 中 RunLoop 的实现原理、工作机制以及实际应用。通过源码分析和实际案例,帮助读者全面理解 RunLoop 在 iOS 系统中的重要作用。

一、RunLoop 基础概念

1. RunLoop 的定义与作用

RunLoop 是 iOS 系统中用于处理事件和消息的循环机制。它负责管理线程的事件处理、消息传递和任务调度,是 iOS 应用能够持续运行并响应用户交互的基础。

主要功能:

  • 保持程序持续运行
  • 处理各种事件(触摸事件、定时器事件、网络事件等)
  • 节省 CPU 资源,提高程序性能
  • 协调线程间的通信

2. RunLoop与线程的关系

  • 每个线程都有且只有一个对应的 RunLoop
  • 主线程的 RunLoop 默认是开启的
  • 子线程的 RunLoop 默认是关闭的,需要手动开启
  • RunLoop 与线程是一一对应的关系
  • RunLoop 的生命周期与线程的生命周期一致

二、RunLoop 的核心组件与底层实现

1. 核心组件及其底层结构

1.1 核心组件层级结构

CFRunLoopRef
├── CFRunLoopModeRef (多个)
│   ├── CFRunLoopSourceRef (Source0)
│   ├── CFRunLoopSourceRef (Source1)
│   ├── CFRunLoopTimerRef
│   └── CFRunLoopObserverRef
├── CFRunLoopCommonModes
└── CFRunLoopCommonModeItems

RunLoop 的核心组件形成了一个完整的层级结构,从顶层到底层依次为:

  1. CFRunLoopRef:RunLoop 的核心,负责管理整个 RunLoop 的生命周期、状态和所有子组件。

  2. CFRunLoopModeRef:RunLoop 的运行模式,用于隔离不同场景下的事件处理,每个 Mode 包含独立的事件源集合。

  3. CFRunLoopSourceRef:RunLoop 的事件源,分为处理应用内部事件的 Source0 和处理系统事件的 Source1。

  4. CFRunLoopTimerRef:RunLoop 的定时器,用于在特定时间点触发事件,支持重复触发和单次触发。

  5. CFRunLoopObserverRef:RunLoop 的观察者,用于监听 RunLoop 的状态变化,支持监控整个生命周期。

1.2 CFRunLoopRef

CFRunLoopRef 是 RunLoop 的核心对象,它包含了 RunLoop 的所有状态和配置信息。在 Core Foundation 中,RunLoop 是一个 C 语言结构体,通过 CFRunLoopRef 进行引用。

底层结构:

struct __CFRunLoop {CFRuntimeBase _base;           // 基础运行时信息pthread_mutex_t _lock;         // 互斥锁,保证线程安全CFStringRef _currentMode;      // 当前运行模式CFMutableSetRef _modes;        // 所有模式集合CFMutableSetRef _commonModes;  // 通用模式集合CFMutableSetRef _commonModeItems; // 通用模式项集合CFRunLoopModeRef _currentMode; // 当前模式引用CFMutableSetRef _sources0;     // Source0 集合,处理应用内部事件CFMutableSetRef _sources1;     // Source1 集合,处理系统事件CFMutableArrayRef _observers;  // 观察者数组,监听 RunLoop 状态变化CFMutableArrayRef _timers;     // 定时器数组,管理定时任务
};

1.3 CFRunLoopMode

CFRunLoopMode 定义了 RunLoop 的运行模式,每个 RunLoop 可以包含多个 Mode,但同一时间只能运行在一个 Mode 下。Mode 的主要作用是隔离不同场景下的事件处理。

底层结构:

struct __CFRunLoopMode {CFRuntimeBase _base;CFStringRef _name;            // 模式名称CFMutableSetRef _sources0;    // Source0 集合CFMutableSetRef _sources1;    // Source1 集合CFMutableArrayRef _observers; // 观察者数组CFMutableArrayRef _timers;    // 定时器数组
};

常见模式:

  • NSDefaultRunLoopMode: App 的默认运行模式,处理大多数输入源和定时器
  • UITrackingRunLoopMode: 界面跟踪模式,用于 ScrollView 滑动时的模式,保证滑动时不受其他模式的影响,保证滑动的流畅性,优先级较高
  • NSRunLoopCommonModes: 这是一个组合模式,包含了 Default Mode 和 Tracking Mode,不是一个真正的模式,而是一个模式的集合,添加到这个模式的事件源,会同时运行在 Default 和 Tracking 模式下
  • GSEventReceiveRunLoopMode: 接收系统事件的内部 Mode,通常用不到
  • kCFRunLoopCommonModes: Core Foundation 中的通用模式,与 NSRunLoopCommonModes 对应

1.4 CFRunLoopSource

CFRunLoopSource 是 RunLoop 的事件源,分为两种类型:

  1. Source0:处理应用内部事件

    • 需要手动标记为待处理
    • 包含一个回调函数,当事件被触发时调用
    • 主要用于处理应用内部事件,如触摸事件、手势事件等
  2. Source1:处理系统事件

    • 基于 Mach Port 的,由系统内核触发
    • 包含一个 Mach Port 和一个回调函数
    • 主要用于处理系统事件,如网络事件、硬件事件等

底层结构:

struct __CFRunLoopSource {CFRuntimeBase _base;uint32_t _bits;              // 标志位,用于标识 Source 的类型和状态pthread_mutex_t _lock;       // 互斥锁,保证线程安全CFIndex _order;              // 优先级顺序,决定处理顺序CFMutableBagRef _runLoops;   // 关联的 RunLoop 集合union {CFRunLoopSourceContext version0;  // Source0 上下文CFRunLoopSourceContext1 version1; // Source1 上下文} _context;
};

1.5 CFRunLoopTimer

CFRunLoopTimer 是基于时间的触发器,用于在特定时间点触发事件。NSTimer 就是基于 RunLoop 的 Timer 实现的。

底层结构:

struct __CFRunLoopTimer {CFRuntimeBase _base;uint16_t _bits;              // 标志位,用于标识 Timer 的状态pthread_mutex_t _lock;       // 互斥锁,保证线程安全CFRunLoopRef _runLoop;       // 关联的 RunLoopCFMutableSetRef _rlModes;    // 运行模式集合CFAbsoluteTime _nextFireDate; // 下次触发时间CFTimeInterval _interval;    // 时间间隔CFTimeInterval _tolerance;   // 时间容差,允许的误差范围uint64_t _fireTSR;          // 触发时间戳CFIndex _order;             // 优先级顺序CFRunLoopTimerCallBack _callout; // 回调函数CFRunLoopTimerContext _context;  // 上下文信息
};

1.6 CFRunLoopObserver

CFRunLoopObserver 用于观察 RunLoop 的状态变化,可以监听 RunLoop 的整个生命周期。

底层结构:

struct __CFRunLoopObserver {CFRuntimeBase _base;pthread_mutex_t _lock;       // 互斥锁,保证线程安全CFRunLoopRef _runLoop;       // 关联的 RunLoopCFIndex _rlCount;           // RunLoop 计数CFOptionFlags _activities;  // 观察的活动CFIndex _order;            // 优先级顺序CFRunLoopObserverCallBack _callout; // 回调函数CFRunLoopObserverContext _context;  // 上下文信息
};

可监听的事件:

  • kCFRunLoopEntry:进入 RunLoop
  • kCFRunLoopBeforeTimers:即将处理 Timer
  • kCFRunLoopBeforeSources:即将处理 Source
  • kCFRunLoopBeforeWaiting:即将进入休眠
  • kCFRunLoopAfterWaiting:从休眠中唤醒
  • kCFRunLoopExit:退出 RunLoop

2. RunLoop 的启动流程

RunLoop 的运行流程是一个循环过程,主要包含以下步骤:

  1. 通知 Observer:即将进入 RunLoop
  2. 通知 Observer:即将处理 Timer
  3. 通知 Observer:即将处理 Source
  4. 处理 Source0(UI 事件、手动触发的 Source0)
  5. 检查是否有待处理的唤醒事件(Source1、Timer 或其他)
    ├─ 有 → 跳转到步骤 9(标记唤醒,无需休眠)
    └─ 无 → 继续
  6. 通知 Observer:即将进入休眠
  7. 进入休眠(等待 Mach Port 消息)
  8. 通知 Observer:从休眠中唤醒
  9. 处理唤醒时收到的消息
    ├─ GCD 主队列任务(最高优先级)
    ├─ 手动唤醒信号(CFRunLoopWakeUp)
    ├─ Source1 事件(触摸/硬件事件)
    └─ Timer 事件(到期的定时器)
  10. 回到步骤 2,继续循环

三、RunLoop 的实际应用

1. 性能优化

1.1 卡顿监控

通过 RunLoop Observer 可以监控主线程的卡顿情况,这是一个非常实用的性能监控工具。以下是一个完整的卡顿监控实现:

class RunLoopMonitor {private var observer: CFRunLoopObserver?private var lastActivity: CFRunLoopActivity = .entryprivate var lastTime: TimeInterval = 0private let semaphore = DispatchSemaphore(value: 0)func startMonitor() {// 创建观察者var context = CFRunLoopObserverContext(version: 0,info: Unmanaged.passUnretained(self).toOpaque(),retain: nil,release: nil,copyDescription: nil)observer = CFRunLoopObserverCreate(kCFAllocatorDefault,CFRunLoopActivity.allActivities.rawValue,true,0,runLoopObserverCallBack,&context)// 将观察者添加到主线程的 RunLoopCFRunLoopAddObserver(CFRunLoopGetMain(), observer, .commonModes)// 在子线程中监控卡顿DispatchQueue.global().async { [weak self] inguard let self = self else { return }while true {// 等待 50mslet semaphoreWait = self.semaphore.wait(timeout: .now() + 0.05)if semaphoreWait == .timedOut { // 超时if self.lastActivity == .beforeSources || self.lastActivity == .afterWaiting {// 检测到卡顿,记录堆栈信息self.logStackInfo()}}}}}private let runLoopObserverCallBack: CFRunLoopObserverCallBack = { (observer, activity, info) inguard let info = info else { return }let monitor = Unmanaged<RunLoopMonitor>.fromOpaque(info).takeUnretainedValue()monitor.lastActivity = activitymonitor.lastTime = Date().timeIntervalSince1970monitor.semaphore.signal()}private func logStackInfo() {// 获取当前线程的堆栈信息let callStackSymbols = Thread.callStackSymbolsprint("卡顿堆栈信息:\(callStackSymbols)")}
}

这段代码实现了一个完整的卡顿监控系统:

  1. 通过 RunLoop Observer 监听主线程 RunLoop 的状态变化
  2. 使用信号量机制检测 RunLoop 是否卡顿
  3. 当检测到卡顿时,记录当前的堆栈信息
  4. 可以设置卡顿阈值(当前设置为 50ms)

1.2 性能优化技巧

1.2.1 合理使用 RunLoop Mode
class ScrollViewOptimizer: NSObject, UIScrollViewDelegate {func scrollViewDidScroll(_ scrollView: UIScrollView) {// 在滚动时暂停某些操作perform(#selector(heavyOperation),with: nil,afterDelay: 0,inModes: [.default])}func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {// 在滚动结束后恢复操作perform(#selector(heavyOperation),with: nil,afterDelay: 0,inModes: [.common])}@objc private func heavyOperation() {// 耗时操作}
}

这段代码展示了如何利用 RunLoop Mode 来优化滚动性能:

  1. 在滚动时,将耗时操作限制在 Default Mode
  2. 在滚动结束后,将操作添加到 Common Modes
  3. 这样可以避免滚动时的性能问题
1.2.2 优化定时器
class TimerOptimizer {private var timer: Timer?private let tolerance: TimeInterval = 0.1 // 100ms 的容差func setupOptimizedTimer() {// 创建定时器timer = Timer(timeInterval: 1.0,target: self,selector: #selector(timerAction),userInfo: nil,repeats: true)// 设置时间容差,提高性能timer?.tolerance = tolerance// 添加到 RunLoopRunLoop.current.add(timer!, forMode: .common)}@objc private func timerAction() {// 执行定时任务print("Timer fired at: \(Date())")}
}

这段代码展示了如何优化定时器的使用:

  1. 设置合理的时间容差,减少系统唤醒次数
  2. 使用 Common Modes 确保定时器在滚动时也能正常工作
  3. 避免在主线程执行耗时操作

2. 常见应用场景

2.1 常驻线程

class BackgroundWorker {private var workerThread: Thread?private var shouldKeepRunning = falsefunc start() {shouldKeepRunning = trueworkerThread = Thread(target: self, selector: #selector(workerThreadEntry), object: nil)workerThread?.start()}@objc private func workerThreadEntry() {autoreleasepool {// 获取当前线程的 RunLooplet runLoop = RunLoop.current// 添加 Port 防止 RunLoop 退出let port = Port()runLoop.add(port, forMode: .default)// 添加观察者监控 RunLoop 状态let observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,CFRunLoopActivity.allActivities.rawValue,true,0) { (observer, activity) inswitch activity {case .entry:print("RunLoop 进入")case .exit:print("RunLoop 退出")default:break}}CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, .defaultMode)// 运行 RunLoopwhile shouldKeepRunning {runLoop.run(mode: .default, before: .distantFuture)}}}func stop() {shouldKeepRunning = falseperform(#selector(stopThread),on: workerThread!,with: nil,waitUntilDone: false)}@objc private func stopThread() {CFRunLoopStop(CFRunLoopGetCurrent())}
}

这段代码实现了一个完整的常驻线程:

  1. 创建并启动工作线程
  2. 在工作线程中设置 RunLoop
  3. 添加 Port 防止 RunLoop 退出
  4. 添加观察者监控 RunLoop 状态
  5. 提供优雅的停止机制

2.2 事件响应优化

class EventResponder {private var eventQueue: [Any] = []private var isProcessing = falsefunc handleEvent(_ event: Any) {eventQueue.append(event)if !isProcessing {isProcessing = trueperform(#selector(processNextEvent),with: nil,afterDelay: 0,inModes: [.default])}}@objc private func processNextEvent() {guard !eventQueue.isEmpty else {isProcessing = falsereturn}let event = eventQueue.removeFirst()processEvent(event)// 继续处理下一个事件perform(#selector(processNextEvent),with: nil,afterDelay: 0,inModes: [.default])}private func processEvent(_ event: Any) {// 实际的事件处理逻辑print("Processing event: \(event)")}
}

这段代码展示了如何优化事件响应:

  1. 使用队列管理事件
  2. 通过 RunLoop 控制事件处理节奏
  3. 避免事件处理阻塞主线程
  4. 支持事件处理的暂停和恢复

四、RunLoop 常见问题与解决方案

1. 常见问题

  1. NSTimer 不触发

    • 原因:RunLoop Mode 不匹配
    • 解决方案:使用 NSRunLoopCommonModes
  2. 子线程任务不执行

    • 原因:子线程 RunLoop 未启动
    • 解决方案:手动启动 RunLoop
  3. 主线程卡顿

    • 原因:RunLoop 中执行耗时操作
    • 解决方案:将耗时操作放到子线程

2. 调试技巧

  • 使用 CFRunLoopObserver 监控 RunLoop 状态
  • 使用 Instruments 的 Time Profiler 分析性能
  • 使用 NSLog 打印 RunLoop 状态变化

总结

RunLoop 是 iOS 系统中处理事件和消息的核心机制,它通过循环处理来保持程序持续运行并响应各种事件。每个线程都有且只有一个对应的 RunLoop,主线程的 RunLoop 默认开启,而子线程需要手动开启。RunLoop 的核心组件包括 CFRunLoopRef、CFRunLoopMode、CFRunLoopSource、CFRunLoopTimer 和 CFRunLoopObserver,它们共同构成了一个完整的事件处理系统。RunLoop 的工作流程包括事件处理、休眠和唤醒等步骤,通过合理使用 RunLoop Mode 和优化定时器,可以有效提升应用性能。在实际应用中,RunLoop 常用于常驻线程、事件响应优化和性能监控等场景。掌握 RunLoop 的原理和应用,对于开发高性能的 iOS 应用至关重要。


如果觉得本文对你有帮助,欢迎点赞、收藏、关注我,后续会持续分享更多 iOS 底层原理与实战经验

相关文章:

iOS RunLoop 深入解析

本文深入探讨 iOS 中 RunLoop 的实现原理、工作机制以及实际应用。通过源码分析和实际案例&#xff0c;帮助读者全面理解 RunLoop 在 iOS 系统中的重要作用。 一、RunLoop 基础概念 1. RunLoop 的定义与作用 RunLoop 是 iOS 系统中用于处理事件和消息的循环机制。它负责管理线…...

软考中级-软件设计师 数据结构(手写笔记)

第一章&#xff1a;基础 基础知识 五大特性 第二章&#xff1a;线性表 第三章&#xff1a;栈和队列 队列 广义表 第四章&#xff1a;树和二叉树 基础知识 树转二叉树和二叉排序树 哈夫曼树 线索二叉树和平衡二叉树 第五章&#xff1a;图 基础知识和邻接矩阵和邻接表 图的遍…...

/var/log/sssd/` 目录解析

/var/log/sssd/ 是 System Security Services Daemon (SSSD) 的专用日志目录,用于记录与身份认证、用户/组信息查询、缓存管理等相关的操作。以下是该目录的详细解析: 1. 目录结构 默认情况下,/var/log/sssd/ 包含以下日志文件: /var/log/sssd/ ├── sssd.log …...

C++负载均衡远程调用学习之Reactor事件触发机制

目录 1.LARV0.2-REACTOR_BUF实现 2.LARV0.2-outpu_buf实现 3.LARV0.2-reactor继承内存管理 4.LARV0.2流程总结 5.LARV0.3-多路IO事件的分析 6.LARV0.3_io_event和event_loop定义 7.LARV0.3_event_loop添加一个事件 8.LARV0.3_event_loop的epoll_wait封装 9.LARV0.3-eve…...

将uni-app前端项目发布到微信小程序体验版

1、修改后端接口调用地址 const REQUEST_CONST {BASE_URL:https://11.22.33.44:9090, } export default REQUEST_CONST 2、登录微信小程序平台&#xff0c;获取AppID 3、配置微信小程序AppID 在项目根目录下找到manifest.json文件&#xff0c;配置微信小程序相关的参数 4、…...

深入理解CSS显示模式与盒子模型

一、CSS显示模式&#xff1a;元素的“性格”决定布局 1. 显示模式基础 CSS显示模式&#xff08;display属性&#xff09;决定了元素在页面中的排列方式和尺寸表现。常见的显示模式有三大类型&#xff1a; 2. 块级元素&#xff08;Block&#xff09; 特点&#xff1a;独占一…...

突破SQL注入字符转义的实战指南:绕过技巧与防御策略

在渗透测试中&#xff0c;SQL注入始终是Web安全的重点攻击手段。然而&#xff0c;当开发者对用户输入的特殊字符&#xff08;如单引号、反斜杠&#xff09;进行转义时&#xff0c;传统的注入方式往往会失效。本文将深入探讨如何绕过字符转义限制&#xff0c;并给出防御建议。 目…...

java网络原理5

一、网络地址转换&#xff08;NAT&#xff09; 1. 原理 - NAT 用于解决 IP 地址不够用的问题 &#xff0c;将 IP 地址分为外网 IP&#xff08;公网 IP&#xff09;和内网 IP&#xff08;私网 IP&#xff09;。内网 IP 如 10.、172.16 - 172.31.、192.168.* 等&#xff0c;家用…...

一种基于光源评估并加权平均的自动白平衡方法(一)

在之前的博文如何在白平衡标定种构建不同类型的白平衡色温坐标系作为实例说明的白平衡色温坐标系的构建中,利用的如下映射矩阵构建色温坐标系: 按照上述论文的说明,是不能直接把Raw域中的每块的RGB带入公式...

基于Docker Compose的Prometheus监控系统一键部署方案

前言 在当今的云原生时代,系统监控已经成为保障业务稳定运行的重要基石。本文旨在提供一个完整的解决方案,帮助您快速搭建一个功能强大的监控系统。通过Docker Compose实现一键部署,结合Prometheus、Grafana、cAdvisor和node-exporter等优秀开源工具,构建一个完整的监控体…...

服务器丢包率测试保姆级教程:从Ping到网络打流仪实战

测试服务器丢包率是网络性能诊断的重要环节&#xff0c;丢包通常由网络拥塞、硬件故障、配置错误或线路质量差导致。以下是多种测试方法的详细步骤和工具说明&#xff1a; 一、基础工具测试&#xff08;无需专业设备&#xff09; 1. 使用 ping 命令 命令示例&#xff1a; bash…...

家庭服务器IPV6搭建无限邮箱系统指南

qq邮箱操作 // 邮箱配置信息 // 注意&#xff1a;使用QQ邮箱需要先开启IMAP服务并获取授权码 // 设置方法&#xff1a;登录QQ邮箱 -> 设置 -> 账户 -> 开启IMAP/SMTP服务 -> 生成授权码 服务器操作 fetchmail 同步QQ邮箱 nginx搭建web显示本地同步过来的邮箱 ssh…...

Ubuntu ZLMediakit的标准配置文件(rtsp->rtmp->hls)

最近在工作中遇到不生成hls资源的问题,后面发现是配置文件有误,特此记录正确的config.ini配置文件,方便查阅。 最终解决方案,通过下面这种格式可以访问到flv视频,具体为什么不太清楚,rtmp格式:rtmp://39.113.48.113:8089/live/1744168516937396175 记录最终解决方案:ht…...

Android 移动开发:ProgressBar(转圈进度条)

目录 Android 移动开发&#xff1a;ProgressBar&#xff08;转圈进度条&#xff09;控件实战介绍 &#x1f4c2; 文件说明 &#x1f9fe; activity_main.xml&#xff08;布局文件&#xff0c;XML&#xff09; &#x1f9fe; MainActivity.java&#xff08;逻辑代码&#xf…...

CSS:选择器-复合选择器

文章目录 1、交集选择器 1、交集选择器 <style>/* 选中类名为rich的元素*/.rich {color: gold;}/* 选中类名为beauty的元素*/.beauty {color: red;}/* 选中类名为beauty的p元素&#xff0c;这种形式&#xff08;元素配合类选择器&#xff09;以后用的很多&#xff01;&am…...

Kafka-可视化工具-Offset Explorer

安装&#xff1a; 下载地址&#xff1a;Offset Explorer 安装好后如图&#xff1a; 1、下载安装完毕&#xff0c;进行新增连接&#xff0c;启动offsetexplorer.exe&#xff0c;在Add Cluster窗口Properties 选项下填写Cluster name 和 kafka Cluster Version Cluster name (集…...

在pycharm中创建Django项目并启动

Django介绍 Django 是一个基于 Python 的开源 Web 应用框架&#xff0c;采用了 MTV&#xff08;Model - Template - View&#xff09;软件设计模式 &#xff0c;由许多功能强大的组件组成&#xff0c;能够帮助开发者快速、高效地创建复杂的数据库驱动的 Web 应用程序。它具有以…...

私有知识库 Coco AI 实战(六):打造 ES Mapping 小助手

开发同学可能经常和字段类型打交道&#xff0c;数据类型本来就不少&#xff0c;新版本可能还有新的数据类型。更重要的是新的字段类型可能会提升某个场景的性能&#xff0c;不知道的话可就亏大发了。所以我们继续打造一个 ES Mapping 小助手。 克隆小助手 我们进入 Coco Serv…...

JavaScript性能优化实战之代码层面性能优化

在前端开发中,JavaScript 的性能直接影响到网站的加载速度、用户体验和交互流畅度。针对代码层面的优化,我们可以从多个方面入手,确保每一行代码都能最大化地发挥效能。接下来,我们将细化并解释每一个优化点。 1️⃣ 避免全局变量污染 全局变量会被整个 JavaScript 代码所…...

基于C++的IOT网关和平台2:github项目ctGateway技术说明书

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 …...

前端基础之《Vue(13)—重要API》

重要的API 一、nextTick() 1、写法 Vue.$nextTick()或者this.$nextTick() 原因&#xff1a; set操作代码是同步的&#xff0c;但是代码背后的行为是异步的。set操作修改声明式变量&#xff0c;触发re-render生成新的虚拟DOM&#xff0c;进一步执行diff运算&#xff0c;找到…...

Python爬虫实战:获取彼岸网高清素材图片

一、引言 在数字化时代,图片素材的需求持续增长。彼岸网提供了丰富的高质量图片资源,其中 4K 风景图片备受用户青睐。借助 Python 爬虫技术,可自动化地从彼岸网获取这些图片,为用户提供便捷的图片素材服务。然而,爬取过程中会遭遇登录验证、反爬机制等问题,需采用相应技…...

拥抱 Kotlin Flow

1. 引言 Kotlin Flow 是 Kotlin 协程生态中处理异步数据流的核心工具&#xff0c;它提供了一种声明式、轻量级且与协程深度集成的响应式编程模型。与传统的 RxJava 相比&#xff0c;Flow 更简洁、更易于维护&#xff0c;尤其在 Android 开发中已成为主流选择。本文将从基础概念…...

winget使用

Get-Command winget winget search qq winget install Tencent.QQ.NT...

C++从入门到实战(十一)详细讲解C/C++语言中内存分布与C与C++内存管理对比

C从入门到实战&#xff08;十一&#xff09;详细讲解C/C语言中内存分布与C与C内存管理对比 前言一、C/C语言中内存分布1.内核空间2.栈3.堆4.数据段5.代码段 二、例题带练巩固C/C语言中内存分布的知识题目讲解题目答案 三、C语言动态内存分配&#xff08;知识回顾&#xff09;3.…...

flutter 专题 一百零四 Flutter环境搭建

Flutter简介 Flutter 是Google开发的一个移动跨平台&#xff08;Android 和 iOS&#xff09;的开发框架&#xff0c;使用的是 Dart 语言。和 React Native 不同的是&#xff0c;Flutter 框架并不是一个严格意义上的原生应用开发框架。Flutter 的目标是用来创建高性能、高稳定性…...

傅里叶与相位偏移

一、简介 大三的《离散数学》。。。。。 傅里叶变换是数学与工程领域的一项革命性工具&#xff0c;其核心思想是将复杂信号分解为简单正弦波的叠加&#xff0c;实现从时域&#xff08;时间维度&#xff09;到频域&#xff08;频率维度&#xff09;的转换。通过这种变换&#x…...

Godot笔记:入门索引

文章目录 前言游戏引擎软件界面关键概念GDScript导出成品创建非游戏应用后记 前言 最近对游戏引擎这块感兴趣&#xff0c;特别是因为游戏引擎自带的很多工具&#xff0c;作为图形化软件的开发应该也不错。 Godot 是一款这几年比较流行的开源游戏引擎。这里记录下入门学习使用 …...

OpenCV实战教程 第一部分:基础入门

第一部分&#xff1a;基础入门 1. OpenCV简介 什么是OpenCV及其应用领域 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;于1999年由Intel公司发起&#xff0c;现在由非营利组织OpenCV.org维护。Ope…...

OpenCV 图像处理核心技术 (第二部分)

欢迎来到 OpenCV 图像处理的第二部分&#xff01;在第一部分&#xff0c;我们学习了如何加载、显示、保存图像以及访问像素等基础知识。现在&#xff0c;我们将深入探索如何利用 OpenCV 提供的强大工具来修改和分析图像。 图像处理是计算机视觉领域的基石。通过对图像进行各种…...

Git从入门到精通-第二章-工具配置

目录 命令行 安装Git 初次运行Git前的配置​ git config基本概念 常用命令 配置用户信息 配置文本编辑器 查看配置 配置别名&#xff08;简化命令&#xff09; 高级配置 换行符处理&#xff08;方便跨平台协作&#xff09; 忽略文件权限变更&#xff08;常用于团队协…...

树状结构转换工具类

项目中使用了很多树状结构&#xff0c;为了方便使用开发一个通用的工具类。 使用工具类的时候写一个类基础BaseNode&#xff0c;如果有个性化字段添加到类里面&#xff0c;然后就可以套用工具类。 工具类会将id和pid做关联返回一个树状结构的集合。 使用了hutool的工具包判空…...

C#基础简述

C#基础详解 一、C#语言概述 C#&#xff08;读作"C Sharp"&#xff09;是微软开发的面向对象的编程语言&#xff0c;运行在.NET平台上。它结合了C的强大功能和Visual Basic的简单性&#xff0c;具有以下特点&#xff1a; ​​面向对象​​&#xff1a;支持封装、继…...

AI赋能烟草工艺革命:虫情监测步入智能化时代

在当今竞争激烈且品质至上的烟草行业中&#xff0c;生产流程的每一个细微环节都关乎着企业的生死存亡与品牌的兴衰荣辱。烟草工艺部门与制丝、卷包车间作为生产链条的核心驱动&#xff0c;犹如精密仪器中的关键齿轮&#xff0c;彼此紧密咬合、协同运转&#xff0c;任何一处的小…...

小刚说C语言刷题—1462小明的游泳时间

1.题目描述 伦敦奥运会要到了&#xff0c;小明在拼命练习游泳准备参加游泳比赛。 这一天&#xff0c;小明给自己的游泳时间做了精确的计时&#xff08;本题中的计时都按 24 小时制计算&#xff09;&#xff0c;它发现自己从 a 时 b 分一直游泳到当天的 c 时 d 分。 请你帮小…...

StarRocks Lakehouse 如何重构大数据架构?

随着数据分析需求的不断演进&#xff0c;企业对数据处理架构的期望也在不断提升。在这一背景下&#xff0c;StarRocks 凭借其高性能的实时分析能力&#xff0c;正引领数据分析进入湖仓一体的新时代。 4 月 18 日&#xff0c;镜舟科技高级技术专家单菁茹做客开源中国直播栏目《…...

用TCP实现服务器与客户端的交互

引言&#xff1a; 这篇文章主要是用TCP构造的回显服务器&#xff0c;也就是客户端发什么&#xff0c;就返回什么。用实现这个过程方式来学会TCP套接字的使用。 一、TCP的特点 TCP是可靠的&#xff1a;这个需要去了解TCP的机制&#xff0c;这是一个大工程&#xff0c;博主后面写…...

用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering

用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering 文章目录 用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering摘要Abstract1. 预备知识1.1 三维的几何表示1.2 计算机中的集合…...

Vue3 Echarts 3D立方体柱状图实现教程

文章目录 前言一、实现原理二、series ——type: "pictorialBar" 简介2.1 常用属性 三、代码实战3.1 封装一个echarts通用组件 echarts.vue3.2 实现一个立方体柱状图&#xff08;1&#xff09;首先实现一个基础柱状图&#xff08;2&#xff09;添加立方体棱线&#x…...

Soildworks怎样在装配体中建立局部剖视图

1思路&#xff1a;建立拉伸切除 2步骤 1-打开点线面显示按钮 2-在装配体中依据某个基准面&#xff08;例如前视基准面&#xff09;建立一个待切除的草图 3-点击顶部工具栏的装配体--->装嫩配体特征---->拉伸切除---Ok 3具体图示 1-点击&#xff0c;使其变成灰色 即…...

基于C++的IOT网关和平台5:github项目ctGateway开发指南

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 …...

虚拟机centos7安装docker

虚拟机CentOS 7上安装 Docker流程 1. 更新系统软件包 需要确保系统软件包是最新的 sudo yum -y update sudo&#xff1a;以超级用户权限执行命令。 yum&#xff1a;CentOS的包管理器工具。 -y&#xff1a;自动确认所有提示&#xff0c;直接执行。 2. 安装 Docker 依赖 在安装 …...

11.Spring Boot 3.1.5 中使用 SpringDoc OpenAPI(替代 Swagger)生成 API 文档

Spring Boot 3.1.5 中使用 SpringDoc OpenAPI&#xff08;替代 Swagger&#xff09;生成 API 文档 1. 项目结构 假设项目名为 springboot-openapi-demo&#xff0c;以下是项目的基本结构&#xff1a; springboot-openapi-demo/ ├── src/ │ ├── main/ │ │ ├─…...

pytorch对应gpu版本是否可用判断逻辑

# gpu_is_ok.py import torchdef check_torch_gpu():# 打印PyTorch版本print(f"PyTorch version: {torch.__version__}")# 检查CUDA是否可用cuda_available torch.cuda.is_available()print(f"CUDA available: {cuda_available}")if cuda_available:# 打印…...

Kubernetes 集群概念详解

Kubernetes 集群概念详解 Kubernetes 集群是由多个计算节点组成的容器编排系统&#xff0c;用于自动化部署、扩展和管理容器化应用。以下是 Kubernetes 集群的核心概念和架构解析&#xff1a; 一、集群基础架构 1. 集群组成要素 graph TBMaster[控制平面] --> Node1[工作…...

BT137-ASEMI机器人功率器件专用BT137

编辑&#xff1a;LL BT137-ASEMI机器人功率器件专用BT137 型号&#xff1a;BT137 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 批号&#xff1a;最新 引脚数量&#xff1a;3 封装尺寸&#xff1a;如图 特性&#xff1a;双向可控硅 工作结温&#xff1a;-40℃~150℃…...

ArcGIS+GPT:多领域地理分析与决策新方案

技术点目录 AI大模型应用ArcGIS工作流程及功能prompt的使用技巧AI助力工作流程AI助力数据读取AI助力数据编辑与处理AI助力空间分析AI助力遥感分析AI助力二次开发AI助力科研绘图ArcGISAI综合应用了解更多 ——————————————————————————————————…...

鸿蒙文件上传-从前端到后端详解,对比jq请求和鸿蒙arkts请求区别,对比new FormData()和鸿蒙arktsrequest.uploadFile

需要权限&#xff1a;ohos.permission.INTERNET 1.nodejs自定义书写上传后端接口 传输过来的数据放在files?.image下 router.post(/upload,(req, res) > {var form new multiparty.Form();form.uploadDirpublic/images/uploads; //上传图片保存的地址(目录必须存在)fo…...

【DBeaver】如何连接MongoDB

MongoDB驱动 在 DBeaver 社区版是没有的&#xff0c;得自己下载 一、下载mongo-jdbc-standalone.jar 二、在工具栏找到数据库&#xff0c;选择驱动管理器 三、在驱动管理器点击新建 四、选择库&#xff0c;添加mongo-jdbc-standalone.jar;然后点击找到类 五、选择设置&#x…...

Unity 粒子同步,FishNet

Github的工程 同步画面 使用FishNet插件同步&#xff0c;可使用这个选项来克隆第二个项目进行测试...