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

iOS 初识RunLoop

iOS 初识RunLoop

文章目录

  • iOS 初识RunLoop
    • RunLoop的概念
    • RunLoop的功能
    • RunLoop和线程的关系
    • RunLoop的结构
      • Mode
      • Observer
      • Timer 和 source
        • 小结
    • RunLoop的核心
    • RunLoop的流程
    • RunLoop的应用
      • AutoreleasePool
      • 响应触控事件
      • 刷新界面
      • 常驻线程
      • 网络请求
      • NSTimer 和 CADisplayLink
        • NSTimer
        • GCDTimer
        • CADisplayLink

RunLoop的概念

一般来说,一个线程一次只能执行一个任务,执行完成后线程就退出,如果我们需要一个机制,让线程能随时处理事件而不退出.

可以将代码理解成下图:

do {//获取消息//处理消息
} while (消息 != 退出)

这种模型通常被称作Event Loop很多系统和框架都有实现在iOS和macOS中就被称作RunLoop.

简单来说RunLoop就是一种循环,通过这种循环得以让应用程序持续运行,让线程可以随时处理事件,并且让线程需要进行事件处理的时候忙起来,在不需要事件处理的时候闲下来.

  • RunLoop是通过内部维护的事件循环来实现对于事件/消息进行管理的一个对象
  • 没有消息处理时,休眠以避免资源占用,有消息需要处理的,立刻被唤醒

从代码上来看RunLoop是一个对象:

struct __CFRunLoop {CFRuntimeBase _base;pthread_mutex_t _lock;  /* locked for accessing mode list */__CFPort _wakeUpPort;   // used for CFRunLoopWakeUp 内核向该端口发送消息可以唤醒runloopBoolean _unused;volatile _per_run_data *_perRunData; // reset for runs of the run looppthread_t _pthread;             //RunLoop对应的线程uint32_t _winthread;CFMutableSetRef _commonModes;    //存储的是字符串,记录所有标记为common的modeCFMutableSetRef _commonModeItems;//存储所有commonMode的item(source、timer、observer)CFRunLoopModeRef _currentMode;   //当前运行的modeCFMutableSetRef _modes;          //存储的是CFRunLoopModeRefstruct _block_item *_blocks_head;//doblocks的时候用到struct _block_item *_blocks_tail;CFTypeRef _counterpart;
};

下面这个图片是一个RunLoop结构的一个概览:

img

RunLoop的功能

  • 保持程序的持续运行
  • 处理app中的各种事件
  • 节省cpu资源,提高程序性能:在需要工作的时候才去工作,在不需要工作的时候就进入休眠状态,在休眠状态是不占用CPU的

RunLoop和线程的关系

RunLoop和线程是一一对应的,app启动之后,程序进入了主线程,apple帮我们在主线程启动了一个RunLoop.如果是我们开辟的子线程,那么需要我们手动开启RunLoop,而且如果你不主动去获取RunLoop的话,那么子线程的RunLoop是不会开启的,他是采用了一个懒加载的形式.

  • 注意:苹果不允许直接创建 RunLoop,只能通过 CFRunLoopGetMain()CFRunLoopGetCurrent() 去获取,其内部会创建一个 RunLoop 并返回给你(子线程),而它的销毁是在线程结束时。

img

RunLoop在线程中的作用主要就是从 input sourcetimer source这里面接受事件,然后在线程中处理事件

输入源 (input source) 异步传递的事件,通常是从其他线程,app发送的消息

计时器源 (Timer source) 同步传递事件,这些事件在计划的时间,间隔触发.

input source 传递异步事件到对应的一个处理程序,并且退出runUntilDate方法.Timer source传递事件到对应处理程序,但是不会退出runLoop.

runUntilDate:方法在指定时间到达前会保持RunLoop 处于运行状态,RunLoop运行时会处理 input source 的各种事件。

这里我们就可以方便理解下面这段代码的意思了

  1. 为什么main函数不会退出
int main(int argc, char * argv[]) {NSString * appDelegateClassName;@autoreleasepool {// Setup code that might create autoreleased objects goes here.appDelegateClassName = NSStringFromClass([AppDelegate class]);}return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

UIApplicationMain内部默认开启了主线程的RunLoop并执行了一段无限循环的代码,UIApplicationMain函数一直没有返回,还在不断的接受处理消息以及等待休眠,所以运行程序之后,会保持持续运行状态.

RunLoop的结构

在 CoreFoundation 里面关于 RunLoop 有5个类:

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef

他们之间的关系如下图:

RunLoop_0.png

一个RunLoop中有多个Mode,每一个mode有属于自己的Observer,Timer,Source.

Mode

Mode也就是模式,一个RunLoop当前只能处于一种Mode中,就好比当前只能是白天或者当前是夜晚.图中可以看到不同Mode之间是互不干扰的,处于各自的世界里面,AMode做了什么和BMode都是没有关系的,这也就是apple为什么会设置成两个状态来管理我们的滑动和默认状态.

apple给我提供了一下几种Mode:

  • kCFRunLoopDefaultModeapp默认的Mode,通常主线程是在这个Mode下运行的
  • UITrackingRunLoopMode界面追踪Mode,让UISrcollView处于滑动的时候就处于这个Mode
  • UIInitializationRunLoopMode:刚启动app就进入的第一个Mode.启动后就不在使用
  • GSEventReceiveRunLoopMode接受系统事件的内部Mode.通常情况下是用不到的
  • kCFRunLoopCommonModes:不会是一个真正意义上的一个Mode,但是如果你把事件丢到这里来,那么不管你处于什么mode,都会触发你想要执行的事件

当我们的程序运行起来的时候,我们就不用去动他了,它就处于一个kCFRunLoopDefaultMode的状态,当你滚动他力,他就会处于UITrackingRunLoopMode的一个状态,如果你想要在这两个状态都可以响应同一个事件的话,那么就要把事情都方法到kCFRunLoopCommonModes中去执行

大部分情况我们只用使用下面的几种

  • kCFRunLoopDefaultMode
  • UITrackingRunLoopMode
  • kCFRunLoopCommonModes

Observer

Observer,这个就相当于观察你上班的状态的人,这里用一个枚举来表示当前RunLoop的状态:

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {kCFRunLoopEntry = (1UL << 0),           // 即将进入 LoopkCFRunLoopBeforeTimers = (1UL << 1),    // 即将处理 TimerkCFRunLoopBeforeSources = (1UL << 2),   // 即将处理 SourcekCFRunLoopBeforeWaiting = (1UL << 5),   // 即将进入休眠kCFRunLoopAfterWaiting = (1UL << 6),    // 刚从休眠中唤醒kCFRunLoopExit = (1UL << 7),            // 即将退出 LoopkCFRunLoopAllActivities = 0x0FFFFFFFU   // 所有的状态
};

Timer 和 source

从结构的那张图可以看到,Mode 中有一个 Timer 的数组,一个 Mode 中可以有多个 Timer。Timer其实就是计时器,工作原理其实是确定一个计时器,然后给一个任务设置开始事件,和多久执行一次的一个Timer,把它注册到RunLoop中去,然后RunLoop就会根据我们注册的一个时间点来实现对应的内容:

注意,RunLoop中的Timer也不一定是准确的,因为RunLoop的执行事件是有一个顺序的,所以我们要处理玩一个事件才可以处理下一个事件,所以按照逻辑上来讲,尽管事件到了我们还是要把上一个事件执行玩才可以执行这个事件,也就是说我们尽管设置了一个是Timer,也要把上一个事件执行完才可以执行下一个任务,所以按道理来说Timer也不一定准确.

Source

Source 是另外一种 RunLoop 要干的活,看源码的话,Source 其实是 RunLoop 的数据源抽象类.

这里apple给我定义了两种Version的source:

  • source0 : 处理 App 内部事件,App 自己负责管理(触发),如 UIEventCFSocket
  • source1:由 RunLoop 内核管理,Mach port 驱动,如 CFMackPortCFMessagePort

Soucre1可以理解成一种线程之间通信的一种方式,在这ARunLoop中,我想让B线程传递东西给我们,那我们就要通过Port来进行一个传递,然后系统将传输的东西包装成 Source1,在线程 A 中监听 port 是否有东西传输过来,接收到后,唤醒 RunLoop 进行处理

小结

上面的 Source/Timer/Observer 被统称为 mode item,一个 item 可以被同时加入多个 mode。但一个 item 被重复加入同一个 mode 时是不会有效果的。如果一个 mode 中一个 item 都没有,则 RunLoop 会直接退出,不进入循环。(所以在下文中我们实现一个常住线程也是给他添加一个item,保证RunLoop不会被退出)

RunLoop的核心

前面我们一直重复的内容是RunLoop的是一个do - while循环,但是按道理来说do-while循环也是会占用cpu的,我们是怎么实现RunLoop的休眠功能呢?

就是它如何在没有消息处理时休眠,在有消息时又能唤醒。这样可以提高CPU资源使用效率 当然RunLoop它不是简单的while循环,不是用sleep来休眠,毕竟sleep这方法也是会占用cpu资源的。那它是如何实现真正的休眠的呢?

那就是:没有消息需要处理时,就会从用户态切换到内核态,用户态进入内核态后,把当前线程控制器交给内核态,这样的休眠线程是被挂起的,不会再占用cpu资源。

img

这里要注意用户态和内核态 这两个概念,还有mach_msg()方法。 内核态 这个机制是依靠系统内核来完成的。

RunLoop是通过通过内部维护的时间循环来对事件/消息进行管理的一个对象

  • 没有消息需要处理时,休眠避免掉资源占用
    • 用户态 -> 内核态
  • 有消息时候,立刻被唤醒
    • 内核态 -> 用户态

RunLoop的流程

Work.png

具体流程:

  1. 通知Observer已经进入RunLoop
  2. 通知 Observer 即将处理 Timer
  3. 通知Observer即将处理source0
  4. 处理sourece0
  5. 如果有soucre1就通知跳转第九步
  6. 通知Observer即将休眠
  7. 线程休眠状态,除非遇到下面的情况:
    • 有Source0
    • Timer到时间执行
    • 外部手动唤醒
    • 为RunLoop设定时间超时
  8. 通知Observer线程刚被唤醒
  9. 处理等待处理事件
    • 如果是 Timer 事件,处理 Timer 并重新启动循环,跳到 2
    • 如果是source1触发,就处理source
    • RunLoop如果手动被触发但尚未超时,重新启动循环
  10. 通知Observer即将退出

在这里插入图片描述

实际上 RunLoop 内部就是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里,直到超时或手动停止,该函数才会返回。

这里不用担心因为一直处于一个while中的时候,我们的线程就一直在运行,会浪费资源,但是实际上并非如此,我们的RunLoop进入休眠调用的函数mach_msg这个函数是内核记别的指令,可以让这个线程进入一个等待的装入,然后需要的时候再唤醒,所以不用担心这个线程的一个占用问题.

RunLoop的应用

AutoreleasePool

首先我们之前讲过主线程创建的时候,会自动生成RunLoop,而主线程注册了两个Observer,来是实现这里的AutoreleasePool的管理:

  • 第一个Observer,这里的Observer是用来监听一个事件Entry这个事件,即将进入 Loop 的时候,创建一个自动释放池,并且给了一个最高的优先级,保证自动释放池的创建发生在其他回调之前,这是为了保证能管理所有的引用计数。
  • 第二个Observer: 监听两个事件,一个 BeforeWaiting,一个 ExitBeforeWaiting 的时候,干两件事,一个释放旧的池,然后创建一个新的池,所以这个时候,自动释放池就会有一次释放的操作,是在 RunLoop 即将进入休眠的时候。Exit的时候,也释放自动释放池,这里也有一次释放的操作。

BeforeWaiting这个含义其实就是指我们当前的一个RunLoop即将休眠了的状态,我们这里就会释放一个旧池子,然后创建一个新的池子,等到RunLoop退出的时候再次销毁池子.

  • 进入RunLoop的时候会创建一个池子
  • 休眠的时候会销毁该池子,在创建一个新池子
  • 退出的时候再次销毁池子

响应触控事件

苹果提前在 App 内注册了一个 Source1 来监听系统事件。

比如,当一个 触摸/锁屏/摇晃 之类的系统事情产生,系统会先包装,包装好了,通过 mach port 传输给需要的 App 进程,传输后,提前注册的 Source1 就会触发回调,然后由 App 内部再进行分发。

  1. 注册一个Souce1来接受事件
  2. 硬件事件的发生
  3. IOKit.framework 生成 IOHIDEvent 事件并由 SpringBoard 接收
  4. SpringBoard 用 mach port 转发给需要的 App
  5. Soucre1触发回调
  6. 回调中 IOHIDEvent 包装成 UIEvent 进行处理或分发

刷新界面

改变Ui的参数他不会立刻更新,他也是通过RunLoop来进行一个更新的

当 UI 需要更新,先标记一个 dirty,然后提交到一个全局容器中去。然后,在 BeforeWaiting 时,会遍历这个容器,执行实际的绘制和调整,并更新 UI 界面。(在休眠和退出)

常驻线程

我们每一次网络请求的时候都会创建一个新的线程,这里为了减小开销,我们其实可以让一个线程常驻,保证线程不被销毁,这样可以让我们的开销减小.

我们在上面说过,一个RunLoop中如果没有Observer/Timer/Source等items,Runloop会自动退出,因此我们创建一个空的port发送消息给Runloop,以至于Runloop不会退出而是一直常驻

这里笔者给出一个案例:

- (void)viewDidLoad {[super viewDidLoad];self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(runThread) object:nil];[self.thread start];self.view.backgroundColor = UIColor.redColor;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event  {[self performSelector:@selector(runTest) onThread:self.thread withObject:nil waitUntilDone:NO];
}
- (void)runTest {NSLog(@"%@", [NSThread currentThread]);
}
- (void)runThread {NSLog(@"开启子线程 %@", self.thread);[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];[[NSRunLoop currentRunLoop] run];
}

然后我们点击空白处

image-20250518135616295

网络请求

网络请求在RunLoop中有以下几个层级:

CFSocket
CFNetwork       ->ASIHttpRequest
NSURLConnection ->AFNetworking
NSURLSession    ->AFNetworking2, Alamofire
  • CFSocket:是最底层的接口,只负责socket通信
  • CFNetwork 是基于 CFSocket 等接口的上层封装,ASIHttpRequest 工作于这一层。
  • 这一次是一个更高级的封装,可以说是新的面向接口的封装
  • NSSURLSession 是 iOS7 中新增的接口,表面上是和 NSURLConnection 并列的,但底层仍然用到了 NSURLConnection 的部分功能 (比如 com.apple.NSURLConnectionLoader 线程),AFNetworking2 和 Alamofire 工作于这一层。

下面来了解一下有关于NSURLConnection的工作流程

使用NSConnection的时候,会传入一个Delegte,当调用了[connection start]后,delegate会不断收到回调.实际上,start 这个函数的内部会会获取 CurrentRunLoop,然后在其中的 DefaultMode 添加了4个 Source0 (即需要手动触发的Source)。CFMultiplexerSource 是负责各种 Delegate 回调的,CFHTTPCookieStorage 是处理各种 Cookie 的

当开始网络传输时,我们可以看到 NSURLConnection 创建了两个新线程:com.apple.NSURLConnectionLoader 和 com.apple.CFSocket.private。其中 CFSocket 线程是处理底层 socket 连接的。NSURLConnectionLoader 这个线程内部会使用 RunLoop 来接收底层 socket 的事件,并通过之前添加的 Source0 通知到上层的 Delegate。

在这里插入图片描述

NSURLConnectionLoader 中的 RunLoop 通过一些基于 mach port 的 Source 接收来自底层 CFSocket 的通知。当收到通知后,其会在合适的时机向 CFMultiplexerSource 等 Source0 发送通知,同时唤醒 Delegate 线程的 RunLoop 来让其处理这些通知。CFMultiplexerSource 会在 Delegate 线程的 RunLoop 对 Delegate 执行实际的回调。

NSTimer 和 CADisplayLink

NSTimer

前面一直有提到Timer source事件源,从上层来看其实他就相当于我们的一个NSTimer

一个NSTimer注册到RunLoop后,RunLoop会为其重复的时间点注册好事件,比方说10 : 00者几个时间点.RunLoop为了节省资源,不会在非常准确的时间点进行一个回调Timer.Timer 有个属性叫做 Tolerance (宽容度),标示了当时间点到后,容许有多少最大误差。由于 NSTimer 的这种机制,因此 NSTimer 的执行必须依赖于 RunLoop,如果没有 RunLoop,NSTimer 是不会执行的。

GCDTimer

使用GCDTimer就不会有这个问题,NSTimer十因为依赖与RunLoop的内容,如果RunLoop的任务繁重,很有可能导致时间不够准确,而采用GCD的计时器就不会有这个问题,因为这里的GCDTimer是依赖于我们的操作系统内核的,所以会更加准确.

CADisplayLink

CADisplayLink是一个执行频率(fps)和屏幕刷新相同(可以修改preferredFramesPerSecond改变刷新频率)的定时器,它也需要加入到RunLoop才能执行。与NSTimer类似,CADisplayLink同样是基于CFRunloopTimerRef实现,底层使用mk_timer(可以比较加入到RunLoop前后RunLoop中timer的变化)。和NSTimer相比它精度更高(尽管NSTimer也可以修改精度),不过和NStimer类似的是如果遇到大任务它仍然存在丢帧现象。通常情况下CADisaplayLink用于构建帧动画,看起来相对更加流畅,而NSTimer则有更广泛的用处。

相关文章:

iOS 初识RunLoop

iOS 初识RunLoop 文章目录 iOS 初识RunLoopRunLoop的概念RunLoop的功能RunLoop和线程的关系RunLoop的结构ModeObserverTimer 和 source小结 RunLoop的核心RunLoop的流程RunLoop的应用AutoreleasePool响应触控事件刷新界面常驻线程网络请求NSTimer 和 CADisplayLinkNSTimerGCDTi…...

备忘录模式

1.意图 备忘录模式是一种行为型设计模式&#xff0c;允许在不破坏封装的特性前提&#xff0c;获取并保存一个对象的内部状态&#xff0c;后续需要时恢复该状态。核心是将对象的状态存储在一个独立的备忘录对象中&#xff0c;并在需要时恢复。 2.模式类型 行为型对象设计模式 …...

UCOS 嵌入式操作系统

UCOS 嵌入式操作系统是一款在嵌入式领域应用广泛且具有重要地位的实时操作系统&#xff0c;以下是对它的详细介绍。 发展历程 初始版本诞生&#xff1a;UCOS 最早由美国嵌入式系统专家 Jean J. Labrosse 于 1991 年开始开发。当时他在项目中需要一个合适的实时操作系统&#…...

redis读写一致问题

title: redis读写一致问题 date: 2025-05-18 11:11:31 tags: redis categories: redis的问题方案 Redis读写一致问题 条件: 数据库此时的数据为10,redis此时的数据也为10 业务流程: 操作数据库使得数据库的数据为20&#xff0c;删除redis里面的数据保证读写一致 先删缓存…...

Redis实现分布式锁的进阶版:Redisson实战指南

一、为什么选择Redisson&#xff1f; 在上一篇文章中&#xff0c;我们通过Redis原生命令实现了分布式锁。但在实际生产环境中&#xff0c;这样的基础方案存在三大痛点&#xff1a; 锁续期难题&#xff1a;业务操作超时导致锁提前释放不可重入限制&#xff1a;同一线程无法重复…...

标准库、HAl库和LL库(PC13初始化)

标准库 (Standard Peripheral Library) c #include "stm32f10x.h"void GPIO_Init_PC13(void) {GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);GPIO_InitStruct.GPIO_Pin GPIO_Pin_13;GPIO_InitStruct.GPIO_Mode GPIO_…...

第二章:安卓端启动流程详解与疑难杂症调试手册

想让一个安卓项目跑起来&#xff0c;从表面看无非就是&#xff1a;双击打开、连接真机、点击运行。 但是到了互动娱乐组件项目里&#xff0c;事情就变成了&#xff1a;点击运行→等待→黑屏→白屏→强制退出→LogCat爆炸→你怀疑人生。 本章就来系统性解决几个问题&#xff1…...

备份C#的两个类

GuestIP依赖项&#xff1a; using System.Data.SQLite; //这是第三方依赖项&#xff0c;要从nuget下载 static class GuestIP {public static void ReadLastGuestIP(string constr "Data Sourceguestip_log.db;"){using (var connection new SQLiteConnection(co…...

通过串口设备的VID PID动态获取串口号(C# C++)

摘要 本篇文章主要介绍分别通过C#和C++使用设备VID PID如何动态获取COM口 目录 1 简述 2 VID PID查看方式 3 C#实现通过串口设备的VID PID动态获取串口号 3.1 辅助类实现 3.2 调用实例 4 C++实现通过串口设备的VID PID动态获取串口号 4.1 辅助类实现 4.2 调用实例 1 简…...

C语言指针深入详解(二):const修饰指针、野指针、assert断言、指针的使用和传址调用

目录 一、const修饰指针 &#xff08;一&#xff09;const修饰变量 &#xff08;二&#xff09;const 修饰指针变量 二、野指针 &#xff08;一&#xff09;野指针成因 1、指针未初始化 2、指针越界访问 3、指针指向的空间释放 &#xff08;二&#xff09;如何规避野指…...

《P5283 [十二省联考 2019] 异或粽子》

题目描述 小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。 小粽面前有 n 种互不相同的粽子馅儿&#xff0c;小粽将它们摆放为了一排&#xff0c;并从左至右编号为 1 到 n。第 i 种馅儿具有一个非负整数的属性值 ai​。每种馅儿的数量都足够多&#xff0c;即小粽…...

C#自定义扩展方法 及 EventHandler<TEventArgs> 委托

有自定义官方示例链接&#xff1a; 如何实现和调用自定义扩展方法 - C# | Microsoft Learn 1.静态类 2.静态方法 3.第一参数固定为this 要修改的类型,后面才是自定的参数 AI给出的一个示例&#xff1a;没有自定义参数 、有自定义参数的 using System; using System.Colle…...

oracle 资源管理器的使用

14.8.2资源管理器的使用 资源管理器控制CPU资源使用说明&#xff1a;  第一种分配方法&#xff1a;EMPHASIS CPU 分配方法确定在资源计划中对不同使用者组中的会话的重视程度。CPU占用率的分配级别为从1 到8&#xff0c;级别1 的优先级最高。百分比指定如何将CPU 资源分配给每…...

(二十一)Java集合框架源码深度解析

一、集合框架概述 Java集合框架(Java Collections Framework, JCF)是Java语言中用于存储和操作数据集合的一套标准架构。它提供了一组接口、实现类和算法&#xff0c;使开发者能够高效地处理各种数据结构。 1.1 集合框架的历史演变 在Java 1.2之前&#xff0c;Java只有几种简…...

spark数据的提取和保存

Spark数据提取和保存 一、数据提取&#xff08;读取数据&#xff09; 1. 读取文件&#xff08;文本、CSV、JSON等&#xff09; scala // 读取文本文件 val textData spark.read.text("路径/文件.txt") // 读取CSV文件&#xff08;带表头&#xff09; val csvD…...

Graphics——基于.NET 的 CAD 图形预览技术研究与实现——CAD c#二次开发

一、Graphics 类的本质与作用 Graphics 是 .NET 框架中 System.Drawing 命名空间下的核心类&#xff0c;用于在二维画布&#xff08;如 Bitmap 图像&#xff09;上绘制图形、文本或图像。它相当于 “绘图工具”&#xff0c;提供了一系列方法&#xff08;如 DrawLine、FillElli…...

vue3_flask实现mysql数据库对比功能

实现对mysql中两个数据库的表、表结构、表数据的对比功能, 效果如下图 基础环境请参考 vue3flasksqlite前后端项目实战 代码文件结构变化 api/ # 后端相关 ├── daos/ │ ├── __init__.py │ └── db_compare_dao.py # 新增 ├── routes/ │ ├── _…...

【数据结构】2-3-1单链表的定义

数据结构知识点合集 知识点 单链表存储结构 优点&#xff1a;不要求大片连续空间&#xff0c;改变容量方便&#xff1b;缺点&#xff1a;不可随机存取&#xff0c;要耗费一定空间存放指针 /*单链表节点定义*/ typedef struct LNode{ElemType data;struct LNode *next; }LNo…...

面试题总结一

第一天 1. 快速排序 public class QuickSort {public static void quickSort(int[] arr, int low, int high) {if (low < high) {// 分区操作&#xff0c;获取基准元素的最终位置int pivotIndex partition(arr, low, high);// 递归排序基准元素左边的部分quickSort(arr, …...

Ubuntu24.04下安装ISPConfig全过程记录

今天在网上看到ISPConfig&#xff0c;觉得不错&#xff0c;刚好手里又有一台没用的VPS,就顺手安装一个玩玩。具体安装步骤如下&#xff1a; 一、配置服务器hosts及hostname 【安装时候需要检查】 使用root账号登录VPS后 先安装vim编辑器&#xff0c;然后编辑hosts&#xff0…...

【NGINX】 -10 keepalived + nginx + httpd 实现的双机热备+ 负载均衡

文章目录 1、主架构图1.1 IP地址规划 2、web服务器操作3、配置nginx服务器的负载均衡4、配置keepalived4.1 master4.1 backup 5、测试双机热备5.1 两台keepalived服务器均开启5.2 模拟master节点故障 1、主架构图 1.1 IP地址规划 服务器IP地址web1192.168.107.193web2192.168.…...

NC016NC017美光固态芯片NC101NC102

NC016NC017美光固态芯片NC101NC102 在存储技术的演进历程中&#xff0c;美光科技的NC016、NC017、NC101与NC102系列固态芯片&#xff0c;凭借其技术创新与市场适应性&#xff0c;成为行业关注的焦点。本文将从技术内核、产品性能、行业动向、应用场景及市场价值五个维度&#…...

C++(22):fstream的一些成员函数

目录 1 遍历读取文件 1.1 eof()方法 2 读取文件大小 2.1 seekg() 2.2 tellg() 2.3 代码实例 3 存取文字 3.1 read() 3.2 write() 3.3 代码实例 3.3.1 存取文字 3.3.2 特殊方法存储 3.3.3 特殊方法读取 4 重载的输入输出 4.1 重载的输出 << 4.2 重载的输…...

【网络】Wireshark练习3 analyse DNS||ICMP and response message

ip.addr 172.16.0.100 && ip.addr 172.16.0.5 && (dns || icmp) 包号 22–31 之所以被选中&#xff0c;是因为在整个抓包文件里&#xff0c;与执行 ping cat.inx251.edu.au 这一事件相关的所有报文&#xff0c;恰好连续出现在第 22 到第 31 条记录中。具体分…...

GBS 8.0服装裁剪计划软件在线试用

1、全新升级内核8.0&#xff0c;分床更合理&#xff0c;铺布床数更少&#xff1b; 2、支持SS AUTONESTER排料引擎切换 3、支持ASTM AAMA及国产CAD&#xff08;如布衣&#xff09;导出的DXF&#xff0c;Prj文件等 4、核心引擎优化 拖料优化 省料优化 5、经实战对比人工&…...

顺 序 表:数 据 存 储 的 “ 有 序 阵 地 ”

顺 序 表&#xff1a;数 据 存 储 的 “ 有 序 阵 地 ” 线 性 表顺 序 表 - - - 顺 序 存 储 结 构顺 序 表 的 操 作 实 现代 码 全 貌 与 功 能 介 绍顺 序 表 的 功 能 说 明代 码 效 果 展 示代 码 详 解SeqList.hSeqList.ctest.c 总 结 &#x1f4bb;作 者 简 介&#xf…...

#Redis黑马点评#(七)实战篇完结

目录 一 达人探店 1 发布探店笔记 2 查看探店笔记 3 点赞功能 ​编辑 4 点赞排行榜&#xff08;top5&#xff09; ​编辑 二 好友关注 1 关注与取关 2 共同关注 3 Feed流实现关注推送 4 实现滚动分页查询 三 附近商店 1 GEO数据结构 2 附近商户搜索功能 四 用户…...

初始C++:类和对象(中)

概述&#xff1a;本篇博客主要介绍类和对象的相关知识。 1. 类的默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。一个类&#xff0c;在不写任何代码的情况下编译器会默认生成以下六个默认函数&#xff0c;在六个默认…...

Java开发经验——阿里巴巴编码规范实践解析3

摘要 本文深入解析了阿里巴巴编码规范中关于错误码的制定与管理原则&#xff0c;强调错误码应便于快速溯源和沟通标准化&#xff0c;避免过于复杂。介绍了错误码的命名与设计示例&#xff0c;推荐采用模块前缀、错误类型码和业务编号的结构。同时&#xff0c;探讨了项目错误信…...

ChatGPT:OpenAI Codex—一款基于云的软件工程 AI 代理,赋能 ChatGPT,革新软件开发模式

ChatGPT&#xff1a;OpenAI Codex—一款基于云的软件工程 AI 代理&#xff0c;赋能 ChatGPT&#xff0c;革新软件开发模式 导读&#xff1a;2025年5月16日&#xff0c;OpenAI 发布了 Codex&#xff0c;一个基于云的软件工程 AI 代理&#xff0c;它集成在 ChatGPT 中&#xff0c…...

iOS 内存分区

iOS内存分区 文章目录 iOS内存分区前言五大分区static、extern、const关键字比较conststaticextern与.h文件的关系extern引用变量extern声明 static和const联合使用extern和const联合使用 前言 笔者之前学习OC源码的时候,发现对于这里的几个static,extern,const的内容有遗忘,所…...

LWIP的Socket接口

Socket接口简介 类似于文件操作的一种网络连接接口&#xff0c;通常将其称之为“套接字”。lwIP的Socket接口兼容BSD Socket接口&#xff0c;但只实现完整Socket的部分功能 netconn是对RAW的封装 Socket是对netconn的封装 SOCKET结构体 struct sockaddr { u8_t sa_len; /* 长…...

【Linux笔记】——线程同步条件变量与生产者消费者模型的实现

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;【Linux笔记】——线程互斥与互斥锁的封装 &#x1f516;流水不争&#xff0c;争的是滔滔不息 一、线程同步的…...

Popeye

概览与定位 Popeye 是由 derailed 团队开源的 Kubernetes 集群资源 “Sanitizer”&#xff0c;它以只读方式扫描集群内的各种资源&#xff08;如 Pod、Service、Ingress、PVC、RBAC 等&#xff09;&#xff0c;并基于社区最佳实践给出问题等级及修复建议&#xff0c;覆盖配置误…...

ES(ES2023/ES14)最新更新内容,及如何减少内耗

截至2023年10月,JavaScript(ECMAScript)的最新版本是 ES2023(ES14)。 ES2023 引入了许多新特性,如findLast、toSorted等,同时优化了性能。通过减少全局变量、避免内存泄漏、优化循环、减少DOM操作、使用Web Workers、懒加载、缓存、高效数据结构和代码压缩,可以显著降低…...

电子数据取证(数字取证)技术全面指南:从基础到实践

为了后续查阅方便&#xff0c;推荐工具先放到前面 推荐工具 数字取证基础工具 综合取证平台 工具名称类型主要功能适用场景EnCase Forensic商业全面的证据获取和分析、强大的搜索能力法律诉讼、企业调查FTK (Forensic Toolkit)商业高性能处理和索引、集成内存分析大规模数据处…...

【通用智能体】Serper API 详解:搜索引擎数据获取的核心工具

Serper API 详解&#xff1a;搜索引擎数据获取的核心工具 一、Serper API 的定义与核心功能二、技术架构与核心优势2.1 技术实现原理2.2 对比传统方案的突破性优势 三、典型应用场景与代码示例3.1 SEO 监控系统3.2 竞品广告分析 四、使用成本与配额策略五、开发者注意事项六、替…...

基于 STM32 的手持式安检金属探测器设计与实现

一、硬件设计:芯片与功能模块选型及接线 1. 主控芯片选型 芯片型号:STM32F103C8T6 核心优势: 32 位 Cortex-M3 内核,主频 72MHz,满足实时数据处理需求64KB Flash+20KB SRAM,支持程序存储与数据缓存丰富外设:2 路 USART、2 路 SPI、1 路 I2C、12 位 ADC,适配多模块通信…...

虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系

虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系 code review! 文章目录 虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系1.Default Pawn与Camera的关系1.1. Default Pawn 是什么&#xff1f;1.2. Default Pawn 的主要组件1.3. Default…...

Spring源码主线全链路拆解:从启动到关闭的完整生命周期

Spring源码主线全链路拆解&#xff1a;从启动到关闭的完整生命周期 一文看懂 Spring 框架从启动到销毁的主线流程&#xff0c;结合原理、源码路径与伪代码三位一体&#xff0c;系统学习 Spring 底层机制。 1. 启动入口与环境准备 原理说明 Spring Boot 应用入口是标准 Java 应…...

飞帆控件:可配置post/get接口

先上链接&#xff1a; post_get_ithttps://fvi.cn/796看一下这个控件的配置&#xff1a; 当 url 有某个 get 参数时&#xff0c;例如某些接口回传的参数。使用这个接口会发生这些&#xff1a; 如果检测到 url 中有该 url 参数则继续执行选择是否从 url 中删除该参数将这个参数…...

Android 自定义悬浮拖动吸附按钮

一个悬浮的拨打电话按钮&#xff0c;使用CardViewImageView可能会出现适配问题&#xff0c;也就是图片显示不全&#xff0c;出现这种问题&#xff0c;就直接替换控件了&#xff0c;因为上述的组合控件没有FloatingActionButton使用方便&#xff0c;还可以有拖动和吸附效果不是更…...

Spring AI Alibaba集成阿里云百炼大模型应用

文章目录 1.准备工作2.引入maven依赖3.application.yml4.调用4.1.非流式调用4.2.流式调用 阿里云百炼推出的智能体应用、工作流应用和智能体编排应用&#xff0c;有效解决了大模型在处理私有领域问题、获取最新信息、遵循固定流程以及自动规划复杂项目等方面的局限&#xff0c;…...

UI-TARS本地部署

UI-TARS本地部署 UI-TARS本地部署 UI-TARS 论文&#xff08;arXiv&#xff09; UI-TARS 官方仓库&#xff1a;包含部署指南、模型下载链接及示例代码。 UI-TARS-Desktop 客户端&#xff1a;支持本地桌面应用的交互控制。 模型部署框架&#xff1a;vLLM本地部署 1.下载项目…...

如何利用内网穿透实现Cursor对私有化部署大模型的跨网络访问实践

文章目录 前言1.安装Ollama2.QwQ-32B模型安装与运行3.Cursor安装与配置4. 简单使用测试5. 调用本地大模型6. 安装内网穿透7. 配置固定公网地址总结 前言 本文主要介绍如何在Windows环境下&#xff0c;使用Cursor接入Ollama启动本地部署的千问qwq-32b大模型实现辅助编程&#x…...

Linux的进程概念

目录 1、冯诺依曼体系结构 2、操作系统(Operating System) 2.1 基本概念 ​编辑 2.2 目的 3、Linux的进程 3.1 基本概念 3.1.1 PCB 3.1.2 struct task_struct 3.1.3 进程的定义 3.2 基本操作 3.2.1 查看进程 3.2.2 初识fork 3.3 进程状态 3.3.1 操作系统的进程状…...

(10)python开发经验

文章目录 1 cp35 cp36什么意思2 找不到pip3 subprocess编码错误4 导出依赖文件包含路径5 使用自己编译的python并且pyinstall打包程序 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;Qt开发 &#x1f448;&#x1f449;python开发 &#x1f448; 1 cp35 cp36什…...

什么是时间戳?怎么获取?有什么用

时间戳的定义 时间戳&#xff08;Timestamp&#xff09;是指记录某个事件发生的具体时间点&#xff0c;通常以特定的格式表示。它可以精确到秒、毫秒甚至更小的单位&#xff0c;用于标识某个时刻在时间轴上的位置。 获取时间戳的方法 在不同的编程语言中&#xff0c;获取时间…...

Zookeeper 入门(二)

4. Zookeeper 的 ACL 权限控制( Access Control List ) Zookeeper 的ACL 权限控制,可以控制节点的读写操作,保证数据的安全性&#xff0c;Zookeeper ACL 权 限设置分为 3 部分组成&#xff0c;分别是&#xff1a;权限模式&#xff08;Scheme&#xff09;、授权对象&#xff08…...

[创业之路-361]:企业战略管理案例分析-2-战略制定-使命、愿景、价值观的失败案例

一、失败案例 1、使命方面的失败案例 真功夫创业者内乱&#xff1a;真功夫在创业过程中&#xff0c;由于股权结构不合理&#xff0c;共同创始人及公司大股东潘宇海与实际控制人、董事长蔡达标产生管理权矛盾。双方在公司发展方向、管理改革等方面无法达成一致&#xff0c;导致…...