RT Preempt linux学习笔记
RT Preempt linux学习笔记
一、实时操作系统(Realtime Operating System)
1. 什么是实时操作系统
A real-time system is a time-bound system which has well-defined, fixed time constraints. Processing must be done within the defined constraints or the system will fail. ——from Wikipedia
实时操作系统要求在一个触发信号到来之后能够在一个确定的时间点之前进行响应处理。它与普通的非实时操作系统区别在于:普通操作系统的响应延时受系统负载影响较大,轻负载时可能会满足响应的要求,但是在负载变大的时候响应会变慢,并且这个响应时间是不确定的。因此一个足够快的系统不代表是一个实时操作系统,实时系统必须要求在负载变化的情况下依然能够满足确定的响应时间,如果无法在确定的时候下完成响应,那么会导致系统错误。
2. 实时操作系统指标
确定性:The same input must always yield the same output
- 在实时系统中,事件和数据处理的时间必须是一致的
- 在多任务系统中,关键任务应该是确定的
- CPU共享和外部中断的影响必须完全可预测
延迟:Time elapsed between an event and the reaction to the event
- 最坏情况下的执行时间很难预测,因此我们需要最坏情况下的反应时间
- 延迟是实时操作系统的主要关注点
二、影响实时性的因素
1. view from software(linux)
从某个事件发生到负责处理这个事件的进程开始执行,过程如下:
(1) 硬件检测到某个事件,发送中断请求信号给中断控制器
(2) 中断控制器把中断请求分发给某个处理器
(3) 处理器响应中断请求,执行中断处理程序
(4) 中断处理程序唤醒负责处理这个事件的实时进程
(5) 进程调度器调度进程,选中负责处理这个事件的实时进程
(6) 实时进程开始执行,处理事件
从上面的过程中,我们可以归纳出影响实时性的几个因素:(进程运行前)
-
中断能否及时响应
-
实时进程能否被及时调度
导致处理器不能及时响应中断的因素有:正在执行中断处理程序,或者正处于执行禁止中断的临界区。
对应的解决方法如下:
(1) 中断线程化,也就是使用内核线程执行中断处理函数
(2) 为了减小时钟中断处理程序的执行时间,把高精度定时器的到期模式分为软中断到期模式(HRTIMER_MODE_SOFT )和硬中断到期模式(HRTIMER_MODE_HARD ),大多数高精度定时器使用软中断到期模式,在软中断里面执行
(3) 如果使用内核线程执行中断处理函数,那么原来禁止硬中断的临界区不需要禁止硬中断,为了兼顾非实时内核和实时内核,引入本地锁(local_lock_t),非实时内核把本地锁映射到禁止内核抢占和禁止硬中断,实时内核把本地锁映射到基于实时互斥锁实现的自旋锁
导致实时进程不能被及时调度的因素如下:
(1) 正在执行软中断
(2 )正在执行禁止软中断(调用函数local_bh_disable())的临界区
(3) 正在执行禁止内核抢占(调用函数preempt_disable())的临界区
(4) 正在执行RCU保护(调用函数rcu_read_lock()或rcu_read_lock_bh())的读端临界区,禁止内核抢占
(5) 正在执行自旋锁或读写锁保护的临界区
(6) 需要申请的锁被优先级低的进程持有,导致优先级高的进程等待优先级低的进程,发生优先级反转
对应的解决方法如下:
(1) 软中断全部由软中断线程执行
(2) 如果软中断全部由软中断线程执行,那么原来禁止软中断的临界区可以变成可抢占的,和软中断线程使用本地锁互斥
(3) 在实时内核中大多数禁止内核抢占的临界区可以变成可抢占的,为了兼顾非实时内核和实时内核,引入本地锁,非实时内核把本地锁映射到禁止内核抢占和禁止硬中断,实时内核把本地锁映射到使用实时互斥锁实现的自旋锁
(4) 实现可抢占RCU,把RCU保护的读端临界区变成可以抢占的
(5) 把自旋锁和读写锁替换为可以抢占的、支持优先级继承的锁
(6) 锁支持优先级继承
上面提到的相关解决办法,其实也就是PREEMTP_RT补丁所做的改动。除了进程运行前的这些因素影响实时性外,我们还得考虑进程运行过程中的因素:
(1) Linux内核使用虚拟内存,对用户空间的内存(包括栈、代码段、数据段以及使用函数malloc()或mmap()动态分配的内存)使用惰性分配的策略,如果实时进程访问的虚拟页没有映射到物理页,那么会触发缺页异常,影响实时性
(2) Linux内核在内存不足的时候会回收物理页或者swap到磁盘,导致实时进程访问的虚拟页没有映射到物理页,影响实时性
对应的解决方法:
(1) C库的内存接口对于heap有二级管理,free了之后并不是马上返回给内核态的,我们可以利用这个原理,在程序运行初期就把要用到的heap给提前申请了,这样相关的内存就hold在用户态了。
(2) 实时进程在main()函数里面使用函数malloc()或mmap()预先分配内存,并且调用函数mlockall(),把所有虚拟页映射到物理页,锁定在内存中,阻止内核回收这些物理页
例子如下:
#include <malloc.h>
#include <sys/mman.h>#define SOMESIZE (100*1024*1024) // 100MBint main(int argc, char *argv[])
{unsigned char *buffer;int i;if (!mlockall(MCL_CURRENT | MCL_FUTURE))mallopt(M_TRIM_THRESHOLD, -1UL);mallopt(M_MMAP_MAX, 0);buffer = malloc(SOMESIZE);if (!buffer)exit(-1);/* * Touch each page in this piece of memory to get it* mapped into RAM*/for (i = 0; i < SOMESIZE; i += 4 * 1024)buffer[i] = 0;free(buffer);....../* <do your RT-thing> */return 0;
}
(3)提前申请好要用的栈空间(提前pagefault,占好位置)
#define MAX_SAFE_STACK (1024*1024)void stack_prefault(void)
{unsigned char dummy[MAX_SAFE_STACK];memset(dummy, 0, MAX_SAFE_STACK);
}int main(int argc, char *argv[])
{stack_prefault();....../* <do your RT-thing> */
}
2. view from hardware
-
一些内存总线可以缓冲访问并创建延迟峰值
-
由于总线控制,DMA访问也会引入延迟
-
NUMA结构的内存—远程节点的访问延迟将更长
-
频率缩放(CPU Frequency scaling)
CPU频率可以通过DVFS动态更改(Dynamic Voltage and Frequency Scaling),调整频率会导致执行时间不确定
-
电源管理功能使用睡眠状态,这会引入延迟:CPU休眠得越深,唤醒它所需的时间就越长
三、抢占模型
打上了PREEMPT_RT补丁后,linux有如下几种抢占模型:
1. CONFIG_PREEMPT_NONE
“No Forced Preemption (Server)”,不可抢占内核。这是传统的抢占模型,目标是使吞吐量最大化。大多数时候提供良好的延迟,但是没有保证,可能偶尔出现长的延迟。这种模型主要用于服务器和科学计算系统。如果希望使内核的处理能力最大化,不考虑调度延迟,那么应该选择这种模型。
2. CONFIG_PREEMPT_VOLUNTARY
“Voluntary Kernel Preemption (Desktop)”,自愿内核抢占。这种模型通过增加抢占点的方式减小延迟。在内核里面选择性地增加了一些抢占点,目的是减小最大调度延迟和对交互事件提供更快的响应,代价是稍微降低吞吐量。当低优先级进程在内核模式执行的时候,在预定的抢占点自愿被抢占。这种模型主要用于桌面系统。它减少了长延迟(几百毫秒到几秒)的发生,但是没有消除。
3. CONFIG_PREEMPT
“Preemptible Kernel (Low-Latency Desktop)”,低延迟可抢占内核。这种模型使除了临界区以外的所有内核代码是可以抢占的。当低优先级进程在内核模式执行的时候,可以非自愿地被抢占。这种模型提供了很低的响应延迟,最坏情况的延迟时间是几毫秒,代价是稍微降低吞吐量和稍微增加运行时开销。这种模型主要用于有毫秒级别延迟需求的桌面系统和嵌入式系统。
4. CONFIG_PREEMPT_RT
“Fully Preemptible Kernel (RT)”,完全抢占内核,也称为实时内核。这种模型把自旋锁和读写锁替换为可以抢占的、支持优先级继承的锁,强制中断线程化,并且引入各种机制来打破长的、不可抢占的临界区。这种模型主要用于延迟要求为100微秒或稍低(几十微秒)的实时系统。
四、为什么linux不是实时操作系统
答:延时具备不确定性。
1. 中断优先级比进程高
linux的中断是运行在中断上下文环境,优先级是比进程高的,所以能随时打断高优先级的任务:
2. 中断响应延时不具备确定性(不支持中断嵌套)
linux在处理中断的时候是关闭中断的,所以中断在执行的时候,其他的中断都进不来,这个设计本身简化了内核,但是对于硬实时的打击是致命的,前面的中断不执行完成,优先级再高的中断也得等着。
比如中断1在执行的过程中,来了中断2,而中断2对应的事情是必须要决定性时延的,由于IRQ1的中断服务程序也是coder写的,我们无法确定这个中断服务程序要执行多久。这显然让高优先级中断2的进入延迟不再具备可预期性。
3. softirq/tasklet优先级比进程高
softirq/tasklet是一个比进程上下文优先级更高的上下文。其代码也是coder写的,执行时间不能保证。
4. 自旋锁(spinlock)
自旋锁引起了持有锁的CPU核的抢占调度的禁止。
假设task1和task2运行在一个核上面,当task1拿到spinlock后,这个核上的抢占调度被禁止,如果在task1持有spinlock的时间内,task2是一个高优先级的实时任务,尽管task2被唤醒,它也不可能立即打断task1的执行,必须等待task1释放spinlock。task1究竟会持有spinlock多久,这个是未知的,所以task2究竟要等多久,也未可知,这显然破坏了决定性的时延。
5. linux特殊的内存管理机制:lazy机制 & swap机制
申请内存并不是马上分配的,而是要访问该内存空间的时候才会去分配,创建页表,这就造成了延时。
已经进入内存的东西,也会由于内核的swap机制,会与磁盘进行交换。把实时任务的内存空间给交换出去
假设一个实时的线程被唤醒得以执行,当执行的时候,发现需要访问的临时变量还没有获得内存,代码段可能还在硬盘里,那它又怎么保证实时性呢?
有人会说,那把高优先级的任务放到中断或者softirq里面跑不就完事了吗?这是裸奔的想法,完全就不是linux了。
记住,linux只提供机制,不提供策略。
6. 内核里面充斥着会屏蔽中断的API如local_irq_disable、spin_lock_irqsave等
spin_lock_irqsave这样的API在内核的使用可以说太常见了,它其实是适用于一个经典的场景,就是中断服务程序与线程之间有竞态的情况。spin_lock_irqsave既屏蔽了抢占,又屏蔽了中断,这会导致中断和实时任务的确定性时延造成不可预期的破坏。因为spin_lock_irqsave和spin_lock_irqrestore是coder写的,谁能保证执行时间呢?
7. 进程调度时机充满不确定性
Linux进程调度时机主要有:
-
进程自愿主动让出(yield)
-
进程状态转换的时刻:进程终止、进程睡眠
-
当前进程的时间片用完时(current->counter=0)
-
进程从中断、异常及系统调用返回到用户态时
大多数多任务操作系统都是抢占式操作系统,包括Linux。当任务在用户态下运行并被中断中断时,如果中断处理程序唤醒另一个任务,则可以在中断处理程序返回时立即调度该任务:
但是,当任务正在执行系统调用时发生了中断,该系统调用必须在调度另一个任务之前完成。这意味着调用调度器来调度另一个任务的时间是不确定的:
/* arch/arm64/kernel/entry-common.c */
el0_sysexit_to_user_modeprepare_exit_to_user_modedo_notify_resumeschedule()
五、preempt_rt补丁改动关键点
1. 中断
强制中断线程化:
在PREEMPT_RT中,几乎所有的中断处理程序都已线程化(未设置IRQF_NO_THREAD标志)。它把顶半部再分成两部分:一部分是硬中断环境,它其实就是一个所谓的“quick check handler”只检查中断源并ack中断最后唤醒对应的中断处理线程,此过程中对应的中断处于disable状态;另一部分是中断处理线程,处理传统顶半部中的剩余部分。如此一来,关中断时间压缩到极限,实时性大大提高。
/* linux-5.15/kernel/irq/manage.c */
int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, unsigned long irqflags,const char *devname, void *dev_id)action->handler = handler;......__setup_irq(irq, desc, action);irq_setup_forced_threadingif (!force_irqthreads()) /* 如果开启了CONFIG_PREEMPT_RT, 这里的force_irqthreads是返回ture的 */return 0;new->thread_fn = new->handler; /* 原来的handler存放到thread_fn,线程化 */new->handler = irq_default_primary_handler; /* handler重新赋值,里面直接return IRQ_WAKE_THREAD*/static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
{return IRQ_WAKE_THREAD;
}
中断线程化是使用内核线程执行中断处理函数,内核线程的名称是“irq/-”(是Linux中断号,是设备名称),调度策略是SCHED_FIFO,实时优先级是50。
2. Softirq
软中断线程化:
在非实时内核中,一部分软中断在中断处理程序的后半部分执行,有时间限制:最多执行10轮,并且总时间不超过2毫秒。剩下的软中断由软中断线程执行,或者在进程开启软中断(调用函数local_bh_enable)的时候执行。每个处理器有一个软中断线程,名称是“ksoftirqd/”(是处理器编号),调度策略是SCHED_NORMAL,优先级是120。
在实时内核中,软中断由软中断线程执行,或者在进程开启软中断的时候执行。中断处理程序的后半部分唤醒当前处理器上的软中断线程。
/* linux-5.15/kernel/softirq.c */
irq_exit__irq_exit_rcuinvoke_softirq#ifdef CONFIG_PREEMPT_RT
static inline void invoke_softirq(void)
{if (should_wake_ksoftirqd())wakeup_softirqd();
}
#else
static inline void invoke_softirq(void)
{if (!force_irqthreads() || !__this_cpu_read(ksoftirqd)) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK__do_softirq();
#elsedo_softirq_own_stack();
#endif} else {wakeup_softirqd();}
}
#endif
3. RCU
解决RCU读端临界区不可抢占的问题:
/* linux-5.15/include/linux/rcupdate.h */
#ifdef CONFIG_PREEMPT_RCU
void __rcu_read_lock(void);
......
#else
static inline void __rcu_read_lock(void)
{preempt_disable();
}
......
#endif
实时内核强制开启可抢占RCU的配置宏CONFIG_PREEMPT_RCU,rcu_read_lock()、rcu_read_unlock()和call_rcu()这些函数使用可抢占RCU实现,所以使用rcu_read_lock()和rcu_read_unlock()保护的读端临界区是可以抢占的。(注:在新版的内核里面,这个可抢占的RCU在开启CONFIG_PREEMPT宏就会默认使用了)
/* linux-5.15/kernel/rcu/tree_plugin.h */
#ifdef CONFIG_PREEMPT_RCU
void __rcu_read_lock(void)
{rcu_preempt_read_enter();if (IS_ENABLED(CONFIG_PROVE_LOCKING))WARN_ON_ONCE(rcu_preempt_depth() > RCU_NEST_PMAX);if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) && rcu_state.gp_kthread)WRITE_ONCE(current->rcu_read_unlock_special.b.need_qs, true);barrier(); /* critical section after entry code. */
}
......
#endif
4. 互斥锁
解决优先级翻转问题:
这里先讲一下,什么是优先级翻转(priority inversion):
假设Task C的优先级低,Task A的优先级高。Task C持有互斥锁,Task A申请互斥锁,因为Task C已经占有互斥锁,所以Task A必须睡眠等待,导致优先级高的Task A等待优先级低的Task C。
如果存在Task B,优先级在Task A和Task C之间,那么情况更糟糕。假设Task C仍然持有互斥锁,Task A正在等待。Task B开始运行,因为它的优先级比Task C高,所以它可以抢占Task C,这就导致Task C持有互斥锁的时间延长,Task A被阻塞,优先级比A低的Task B反而可以运行。
**优先级继承(priority inheritance) **可以解决优先级反转问题。如果低优先级的进程持有互斥锁,高优先级的进程申请互斥锁,那么把持有互斥锁的进程的优先级临时提升到申请互斥锁的进程的优先级。在上面的例子中,把Task C的优先级临时提升到Task A的优先级,防止Task B抢占进程Task C,使Task C尽快执行完临界区,减少Task A的等待时间:
为了实现优先级继承,内核引入了rt-mutex:
/* linux-5.15/include/linux/rtmutex.h */
/*** The rt_mutex structure** @wait_lock: spinlock to protect the structure* @waiters: rbtree root to enqueue waiters in priority order;* caches top-waiter (leftmost node).* @owner: the mutex owner*/
struct rt_mutex {struct rt_mutex_base rtmutex;
#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;
#endif
};struct rt_mutex_base {raw_spinlock_t wait_lock; /* 实时锁,使用优先级排队,使用优先级继承算法解决优先级翻转问题,与task_struct强偶合 */struct rb_root_cached waiters;struct task_struct *owner;
};
5. 自旋锁
自旋锁(spinlock_t)保护的临界区是不可抢占的,导致实时进程不能被及时调度。实时内核使用实时互斥锁实现自旋锁,临界区是可以抢占的,支持优先级继承,spin_lock_irq()和spin_lock_irqsave()不会禁止硬中断。
#ifdef CONFIG_PREEMPT_RT
typedef struct spinlock {union {struct raw_spinlock rlock;......}
} spinlock_t;
#else
/* PREEMPT_RT kernels map spinlock to rt_mutex */
#include <linux/rtmutex.h>
typedef struct spinlock {struct rt_mutex_base lock;
} spinlock_t;
#endif
/* linux-5.15/include/linux/spinlock.h */
static __always_inline void spin_lock(spinlock_t *lock)
{raw_spin_lock(&lock->rlock); /* 里面是会调用preempt_disable来关抢占 */
}/* linux-5.15/include/linux/spinlock_rt.h */
static __always_inline void spin_lock(spinlock_t *lock)
{rt_spin_lock(lock);
}void __sched rt_spin_lock(spinlock_t *lock)
{spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);__rt_spin_lock(lock);
}static __always_inline void __rt_spin_lock(spinlock_t *lock)
{___might_sleep(__FILE__, __LINE__, 0);rtlock_lock(&lock->lock);rcu_read_lock();migrate_disable();
}
少数使用自旋锁保护的临界区不允许抢占,内核定义了原始自旋锁(raw_spinlock)。在非实时内核中,spinlock和raw_spinlock完全相同。
6. hrtimer
在hrtimer引入以前,linux内核的timer精度和编译时配置选项CONFIG_HZ有关,此配置选项有100、250和1000等几个少数值可选,意思是1秒内分别触发100次、250次、1000次timer中断,分别对应10ms、4ms和1ms的精度。显而易见CONFIG_HZ配得越大,timer中断次数越多,处理时钟中断的负载越高,所以CONFIG_HZ不能太大,但1ms的精度对于实时性系统又太差了。在linux-2.6.16中引入hrtimer(High Resolution Timer)的支持,timer中断和CONFIG_HZ脱钩,系统能在硬件timer的精度允许范围内触发中断,故其精度通常能达到纳秒级,具体精度和系统底层硬件提供的timer有关,比如若底层硬件有25MHZ的时钟,那么理论上hrtimer可以提供40纳秒精度的timer。
六、减少延时(latency)的一些措施
1. CPU 绑定(CPU Pinning)
-
Linux内核调度程序允许设置有关允许运行每个任务的CPU内核的约束
-
确保进程不会迁移到另一个核心
-
这种机制称为进程的cpu亲和性
-
使用cpuset子系统和sched_setffinity系统调用来选择cpu
-
使用taskset -p 在指定的cpu上启动一个新进程
2. CPU隔离(CPU Isolation)
用户可以通过CPU亲和机制将进程绑定到CPU内核上,但是内核也可能在这些cpu上调度其他进程。
-
Isolcpus可以在内核命令行上传递
-
调度程序不会使用隔离的cpu
cpuset是一种允许细分CPU调度池的机制,它们在运行时通过cpusetfs创建:
mount -t cpuset none /dev/cpuset
在cpuset主目录中随意创建cpuset:
mkdir /dev/cpuset/rt-set
mkdir /dev/cpuset/non-rt-set
每个cpu被分配一个cpu核池:
echo 2,3 > /dev/cpuset/rt-set
echo 0,1 > /dev/cpuset/non-rt-set
我们可以选择在每个集合中运行哪个任务:
echo PID > /dev/cpuset/non-rt-set/tasks
echo PID > /dev/cpuset/rt-set/tasks
3. 中断亲和度(IRQ affinity)
- 中断由特定的CPU核心处理
- 处理中断的默认CPU是CPU 0
- 在多cpu系统上,可以很好地平衡cpu之间的中断处理
- irq可以通过调整/proc/irq/XX/smp_affinity来固定到cpu上
4. 内存管理
当要求内核分配一些内存时,linux会给应用程序一个虚拟地址范围,这个虚拟范围在访问时才会被映射到一个物理内存范围,这将为应用程序引入page fault延迟。所有内存都应该在应用程序初始化时锁定并访问。在初始化时访问内存称为内存预设(prefaulting)。这涉及堆内存,也涉及栈。
- 在init时调用mlockall(MCL_CURRENT | MCL_FUTURE)来锁定所有内存区域
- 分配所有内存并在初始化时访问它
- 不要调用fork(),因为子进程将会copy-on-write页面
- 配置malloc不返回分配的空间给系统
mallopt(M_TRIM_THRESHOLD, -1)
5. 相关锁的使用
- 在创建多线程应用程序时,使用pthread_mutex_t
- 避免使用没有owner的信号量
- 开启优先级继承(PI):
pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
6. 关闭某些内核配置
一些配置选项不适合在实时运行的时候开启:
-
CONFIG_LOCKUP_DETECTOR
-
CONFIG_DETECT_HUNG_TASK
-
CONFIG_DEBUG_*
-
CONFIG_ARM_CPUIDLE
Why? Because 优先级为99的内核任务可能会引入延迟;由于大量的日志记录,它们中的大多数都会引入延迟
7. 减少printk的使用
传统linux内核中printk可在关中断、禁止抢占的上下文环境中调用,printk最终会调用console driver输出,而console driver一般会利用spinlock进行互斥,在PREEMPT_RT环境中,spinlock是可睡眠的锁,故而printk有可能导致在关中断、禁止抢占的情形下睡眠,这是不能接受行为。
8. MISC
少用fork & mmap系统调用 ,实在不可避免也是静态使用。少用signal & semaphore,这些同步原语是可睡眠的,进程切换出去开销太大了。
相关文章:

RT Preempt linux学习笔记
RT Preempt linux学习笔记 一、实时操作系统(Realtime Operating System) 1. 什么是实时操作系统 A real-time system is a time-bound system which has well-defined, fixed time constraints. Processing must be done within the defined constra…...

JavaScript 基础第四天笔记
JavaScript 基础 - 第4天笔记 理解封装的意义,能够通过函数的声明实现逻辑的封装,知道对象数据类型的特征,结合数学对象实现简单计算功能。 理解函数的封装的特征掌握函数声明的语法理解什么是函数的返回值知道并能使用常见的内置函数 函数 …...

Unity 2021.x及以下全版本Crack
前言 最近Unity那档子事不出来了吗,搞得所有人都挺烦的,顺便在公司内网需要我完成一个游戏的项目,就研究了一下如何将Unity给Crack掉。 注意所有操作应有连接外网的权限 以我选择的版本为例,我使用的是Unity 2021.3.5f1与Unity…...

基于知识蒸馏的夜间低照度图像增强及目标检测
源自:应用光学 作者:苗德邻, 刘磊, 莫涌超, 胡朝龙, 张益军, 钱芸生. “人工智能技术与咨询” 发布 摘要 为了实现夜间低照度图像的增强,提高目标检测模型在夜间低照度条件下的检测精度并减小模型的计算成本,提出了一种基…...

4、ARM异常处理
一、异常处理 1、异常 概念 处理器在正常执行程序的过程中可能会遇到一些不正常的的事件发生,这时处理器就要将当前的程序暂停下来转去处理这个异常的事件,异常事件完成后再返回到之前被异常打断的点继续执行 2、异常处理机制 不同的处理器对异常的…...

【Element-UI】CUD(增删改)及form 表单验证(附源码)
目录 一、导言 1、引言 2、作用 二、CUD 1、增加修改 1.1、添加弹窗 1.2、定义变量 1.3、定义方法 1.4、完整代码 2、删除 2.1、定义方法 三、表单验证 1、添加规则 2、定义规则 3、提交事件 4、前端完整代码 一、导言 1、引言 增删改是计算机编程和数据库管理…...
2024年高新技术企业认定标准
1高新技术企业认定八大条件是什么 (1)企业申请认定时须注册成立一年以上。 (2)企业通过自主研发、受让、受赠、并购等方式,获得对其主要产品(服务)在技术上发挥核心支持作用的知识产权的所有权。 (3)对企业主要产品(服务)发挥核心支持作用的技术属于《国家重点支持的…...
励磁工作原理
励磁工作原理是指在电磁设备中通过外加电流或磁场来增强设备中的磁场强度的过程。在电磁设备中,励磁是非常重要的步骤,它能够保证设备正常运行,并实现设备的预期功能。本文将从基本概念、工作原理和应用方面介绍励磁工作原理。 我们来了解…...
【JAVA】获取当前项目的classpath路径
在Java中可以通过以下几种方式获取classpath路径: ClassLoader的getResource方法 String classpath ClassLoader.getSystemResource("").getPath();Web项目 ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(); String classpath c…...
Sulfo CY3-DBCO蛋白质标记实验-星戈瑞
Sulfo CY3-DBCO是一种荧光标记剂,可以通过点击化学方法将其与蛋白质特异性地标记。以下是一种常见的Sulfo CY3-DBCO蛋白质标记的方法: 实验步骤: 制备目标蛋白质:准备并提取您感兴趣的蛋白质。这可以通过细胞培养、细胞溶解、组织…...
【不规范bug注意】2023.9.26
eigen库的矩阵操作 mn 点乘 n*m 才可以得到一个数。前后大小不满足转置相等关系的有可能可以进行运算而不报错,但结果没有任何意义?多次运行会报段错误 segmentation fault ! 因为访问了未知区域内存? 错误例子 (m * 1) * ( m * 1…...

it端到端运维监控
公司的运维监控已成为确保业务顺利运行的关键。特别是对于IT部门,端到端运维监控不仅可以帮助企业及时发现和解决问题,还可以提高业务效率,优化客户体验。本文将详细介绍端到端运维监控的概念、重要性及其实施方法。 端到端操作监控的概念 端…...
Vue3根组件设置Transition失效的问题
🍁 作者:知识浅谈,CSDN博客专家,阿里云签约博主,InfoQ签约博主,华为云云享专家,51CTO明日之星 📌 擅长领域:全栈工程师、爬虫、ACM算法 💒 公众号:…...

2023-2024年最新大数据学习路线
文章目录 2023-2024年最新大数据学习路线大数据开发入门*01*阶段案例实战 大数据核心基础*02*阶段案例实战 千亿级数仓技术*03*阶段项目实战 PB级内存计算04阶段项目实战 亚秒级实时计算*05*阶段项目实战 大厂面试*06* 2023-2024年最新大数据学习路线 新路线图在Spark一章不再…...

Cocos Creator3.8 实战问题(三)去除scrollview背景色和label 对齐方式设置无效问题
1、 scrollview 默认背景是白色的, 我们不想要 scrollview 默认的背景颜色,怎么办? 设置 scrollview的color为透明吗? 不对,这会导致 view节点完全透明。 解决方法:直接删除scrollview 的Spritre frame就…...

以太坊代币标准ERC20、ERC165、ERC721
两个概念 ERC(Ethereum Request for Comment) 以太坊意见征集稿EIP(Ethereum Improvement Proposals)以太坊改进提案 ERC和EIP用于使得以太坊更加完善;在ERC中提出了很多标准,用的最多的标准就是它的Token标准; 有哪些标准详细见https://eips.ethereum…...
spring cloud gateway谓词工厂 Predicate Factory
Predicate Factory 称为谓词工厂或断言工厂 默认的工厂类都位于 org.springframework.cloud.gateway.handler.predicate 包下 根据版本不同有多有少 本文spring-cloud.version2021.0.5 spring-cloud-gateway3.1.4 官方文档:https://docs.spring.io/spring-cloud-gat…...
美丽塔O(n)解法单调栈
题目 见上一篇: 较难算法美丽塔时间复杂度O(n)-CSDN博客 时间复杂度 O(n) 分析 接着上篇。从左向右依次处理Left,处理Left[i]时,从右向左寻找第一个符合maxHeights[j]<maxHeights[i]的j。如果j1<j2,且maxHeights[j1]&g…...

的PDF文件压缩软件PDF Squeezer mac中文版软件特点
PDF Squeezer mac是一款macOS平台上的PDF文件压缩软件,可以帮助用户快速地压缩PDF文件,从而减小文件大小,使其更容易共享、存储和传输。PDF Squeezer使用先进的压缩算法,可以在不影响文件质量的情况下减小文件大小。 PDF Squeezer…...

JS Ajax 封装
ajax 封装 一、 什么是Ajax?二、 Ajax的优缺点?2.1 优点2.2 缺点 三、 Ajax的使用3.1 状态码3.2 xhr的基本使用3.3 ajax原生封装:3.3.1 触发GET请求:3.3.2 调用POST请求: 四、Ajax的约束 一、 什么是Ajax? …...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

未授权访问事件频发,我们应当如何应对?
在当下,数据已成为企业和组织的核心资产,是推动业务发展、决策制定以及创新的关键驱动力。然而,未授权访问这一隐匿的安全威胁,正如同高悬的达摩克利斯之剑,时刻威胁着数据的安全,一旦触发,便可…...