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

定时器设计

定时器设计的必要性

服务器中的定时器设计具有多方面的必要性,主要体现在以下几个关键方面:

  • 任务调度与管理
    定时任务执行:服务器常常需要执行一些定时性的任务,如定时备份数据、定时清理缓存、定时更新系统日志等。通过定时器可以精确地设置任务的执行时间和周期,确保这些任务按照预定的计划自动执行,无需人工干预,提高服务器的自动化管理水平。
    资源合理分配:服务器资源有限,通过定时器可以合理分配资源在不同任务之间的使用时间。例如,在业务低谷期定时启动一些耗时的维护任务,避免在业务高峰期占用过多资源,影响正常业务处理。
  • 连接管理与优化
    连接超时处理:服务器需要处理大量的客户端连接,对于长时间没有活动的连接,定时器可以设置超时时间,当连接超过规定时间没有数据传输时,自动关闭连接,释放服务器资源,防止大量无效连接占用资源,提高服务器的并发处理能力。
    心跳检测:通过定时器定期向客户端发送心跳包,检测客户端的连接状态。如果客户端在一定时间内没有响应心跳包,服务器可以判断客户端可能出现异常,进而采取相应的措施,如关闭连接或进行重连尝试,保证连接的稳定性和可靠性。
  • 性能监控与维护
    性能指标统计:定时器可以定时触发对服务器性能指标的统计,如 CPU 使用率、内存使用率、网络带宽利用率等。通过定期收集这些数据,管理员可以及时了解服务器的性能状况,发现潜在的性能问题,为性能优化和资源调整提供依据。
    故障检测与恢复:定时检查服务器的关键组件和服务状态,当发现某个服务出现故障或异常时,定时器可以触发相应的恢复机制,如自动重启服务、切换到备用服务器等,尽可能减少故障对业务的影响,提高服务器的可用性和稳定性

2 定时器设计的两种模式

对于服务端来说,驱动服务端逻辑的事件主要有两个,⼀个是⽹络事件,另⼀个是时间事件

2.1 网络事件和定时事件在一个线程中处理

协同处理原理

在服务器编程中,基于事件驱动的网络 IO 模型(如 reactor 模型)是常见的处理方式。这里的 IO 处理同步,意味着当进行网络 IO 操作(如读取或写入网络数据)时,线程会等待操作完成,直到数据可读或可写。而事件处理(包括定时任务处理)是异步的,即不需要等待定时任务时间到达才去执行后续操作,程序可以继续处理其他事情,当定时时间到达时,系统会自动触发相应的处理逻辑
利用 IO 多路复用(如 epoll、kqueue 等)机制,它可以同时监控多个文件描述符(对应网络连接等)的状态变化。在这种机制下,通过设置 epoll_wait () 等函数的 timeout 参数来模拟定时器功能。

具体流程

  • 确定等待时间:首先获取最近要触发的定时任务的触发时间与当前时间的差值,将这个差值作为 epoll_wait () 函数的 timeout 参数。例如,如果最近的定时任务还有 5 秒触发,那么 timeout 就设为 5 秒。
  • 阻塞等待:调用 epoll_wait () 函数,线程进入阻塞状态。在这期间,如果没有网络事件发生,当等待时间超过设定的 timeout,就会先去处理定时任务。比如,5 秒内没有网络连接的读写事件,那么就执行到期的定时任务。
  • 事件处理顺序:若在等待过程中收到网络事件(如客户端发送了新数据,对应的网络连接的文件描述符状态变为可读),则 epoll_wait () 返回,先处理网络事件。处理完网络事件后,再去轮询处理定时事件。比如先读取并处理完客户端发送的数据,再检查并执行到期的定时任务。

应用场景

  • 单 reactor 场景(以 redis 为例):Redis 采用单 reactor 模式,在一个线程中处理网络请求和定时任务。它适用于业务逻辑相对简单、对性能要求高且定时任务不是特别多的场景。因为单线程处理避免了线程切换带来的开销,能高效处理大量的短小请求,同时定时任务也能在合适的时机得到处理。
  • 多 reactor 场景(以 memcached、nginx 为例):memcached 和 nginx 采用多 reactor 模式,主 reactor 负责监听新连接,将连接分配给子 reactor,子 reactor 在各自线程中处理网络事件和定时任务。这种模式适用于高并发场景,能充分利用多核 CPU 的性能,同时在每个子 reactor 线程内也能较好地协调网络事件和定时任务的处理,不过定时任务不能过于繁重,否则会影响网络事件的及时处理。

在同一个线程中处理网络事件和定时任务时,若定时任务即将执行但此时线程还在处理网络事件,可按以下方式处理:
基于 IO 多路复用的处理策略
一般通过 IO 多路复用机制(如 epoll )来协调。在设置 epoll_wait 的 timeout 参数时,是依据最近要触发的定时任务时间来确定的。当 epoll_wait 返回有网络事件时,线程先处理网络事件。处理网络事件过程中,定时任务时间到达也不会立即中断处理 。等网络事件处理完毕,再去检查并执行到期的定时任务。这是因为在单线程内,为保证数据一致性和避免复杂的中断处理逻辑,优先完整处理完当前网络事件。例如在 Redis 中,即使在处理网络请求时定时任务时间到了,也会等请求处理完再去处理定时任务 。
任务优先级与抢占机制(有限应用)
从理论上,若要提高定时任务的实时性,可引入任务优先级和抢占机制。但在单线程场景下,实现复杂且易引发问题。若定时任务优先级极高,可设计在网络事件处理函数中定期检查定时任务状态(比如每处理完一批网络数据检查一次 ),一旦发现有高优先级定时任务到期,暂停当前网络事件处理(需保存好上下文 ),先去执行定时任务,执行完再恢复网络事件处理。不过这种方式会增加代码复杂度和出错风险,实际应用中较少采用,因为可能破坏单线程内操作的原子性和一致性,引发数据竞争等问题。

2.2 网络事件和定时事件在不同线程中处理

  • 创建定时任务检测线程:专门创建一个独立的线程,这个线程的职责就是检测定时任务。它以 sleep (time) 作为定时器驱动,这里的 time 要小于最小时间精度,比如最小时间精度是 100 毫秒,那么 time 可以设为 50 毫秒。
  • 循环检测与处理:在这个线程中,不断循环更新定时器的状态。线程处于休眠状态等待定时事件,当设定的时间到达时,通过信号(如 Linux 下的信号机制,向负责业务逻辑的线程发送特定信号)或者将任务插入运行队列(由其他线程从队列中取出任务并执行)的方式,让其他线程去执行业务逻辑。例如,当一个定时任务到期,该线程向业务线程发送信号,业务线程收到信号后执行相应的定时任务操作。

3 基本数据结构简介

3.1按触发时间顺序组织

**红黑树建议了解一下 **

3.1.1 跳表

下图是一个简单的有序单链表,单链表的特性就是每个元素存放下一个元素的引用。即:通过第一个元素可以找到第二个元素,通过第二个元素可以找到第三个元素,依次类推,直到找到最后一个元素。
请添加图片描述
现在我们有个场景,想快速找到上图链表中的 10 这个元素,只能从头开始遍历链表,直到找到我们需要找的元素。查找路径:1、3、4、5、7、8、9、10。这样的查找效率很低,平均时间复杂度很高O(n)

先在索引找 1、4、7、9,遍历到一级索引的 9 时,发现 9 的后继节点是 13,比 10 大,于是不往后找了,而是通过 9 找到原始链表的 9,然后再往后遍历找到了我们要找的 10,遍历结束。有没有发现,加了一级索引后,查找路径:1、4、7、9、10,查找节点需要遍历的元素相对少了,我们不需要对 10 之前的所有数据都遍历,查找的效率提升了。

那如果加二级索引呢?如下图所示,查找路径:1、7、9、10。是不是找 10 的效率更高了?这就是跳表的思想,用“空间换时间”,通过给链表建立索引,提高了查找的效率。
请添加图片描述
到这里大家应该已经明白了什么是跳表。跳表是可以实现二分查找的有序链表。

相对于黑红树 它的优势就是范围输出

3.1.2 最小堆

请添加图片描述
上面这种类型的数据结构我们将它称为二叉堆。二叉堆在逻辑上虽然是完全二叉树,但是它却是以1为起点的一维数组表示的。假设表示二叉堆的数组为A,二叉堆的大小(元素的数量)为H,那么二叉堆的元素就存储在 A[1, … , H] 中,其中根的下标是1.观察可以发现,只要一个结点的下标i确定了,那么它的父节点就是floor(i/2),左子结点下标是2i, 右子结点的下标是2i+1。

二叉堆和完全二叉树的区别之一在于,二叉堆中存储的各结点的键值需要保证堆具有以下性质之一
最大堆性质: 结点的键值都小于等于其父结点的键值。

·最小堆性质: 结点的键值都大于等于其父结点的键值。

取最小值操作高效时间复杂度低:最小堆查询顶节点(即最小值)的时间复杂度为 (O(1)) ,能直接获取最小值 。而红黑树查找最小值需要从根节点开始,沿着左子树不断向下遍历,时间复杂度为 (O(\log N)) (N 为节点数 ) 。在频繁获取最小值的场景,如优先队列、任务调度系统中确定最早执行任务等,最小堆效率明显更高 。
结构简单,实现难度低原理与代码实现:最小堆原理直观,只需满足父节点小于子节点,实现代码相对简洁。红黑树要满足多种平衡规则(如节点颜色规则、路径黑色节点数相同等 ) ,插入、删除操作需复杂的旋转和颜色调整来维持平衡,实现难度大,代码出错风险高 。数据局部性好内存访问优势:**最小堆常以数组存储,**在内存中数据连续。CPU 缓存预取机制能利用这种数据局部性,访问相邻元素时可直接从缓存获取,减少内存访问开销。红黑树节点通过指针链接,内存分布分散,缓存命中率低,性能受影响 。

3.2 时间轮

为了不产生过多的定时器,我们只使用一个定时器,将所有的定时任务放到一个队列中,每个定时任务都保存一份自己的定时信息,定时器每隔一个周期轮询一遍队列中的所有任务,如果任务的超时时间已到,则执行该任务,如果超时时间还没到,则将该任务的定时信息减掉一个定时器的时间间隔,等到完全减为0时,该任务就可以被执行了, 这个定时器一直这么执行并轮询下去.假设当前定时任务总数有100个,那定时器每个周期会遍历一个100个元素的队列,听上去还可以,那要有1000个的时候,10000个时候,这定时器就太可怜了,像一头老牛
在这里插入图片描述
为了解决任务队列中任务太多,一个定时器压力太大的问题,我们继续对其进行优化,既然所有的定时任务都放在一个队列下不太行,那就对定时任务进行分类,将定时周期相同的任务放在同一个定时器下,这样每个定时器的压力就会大大减小,每个定时器只负责自己周期内的任务,不负责其他周期的任务.但是如果每个任务的周期都相同,还是要产生很多定时器,似乎还是无法从根本上解决问题…
在这里插入图片描述
这时候时间轮的优势就体现出来了,我们设置一个环状的时间队列,队列上的每一个元素,我们称为一个槽(slot),这个槽所对应的时间在整个时间轮里是唯一的, 根据前面的分析也能知道,槽里面是放任务的,而且肯定不会放一个任务,而是放一个任务队列.

对这个环状队列,我们维护一个指针,指针指向的槽,就是已经到达超时时间的槽,槽里的任务就要被执行.任务在被插入时间轮的时候,就根据当前时间以及自己的时间周期,确定好了自己会处于时间轮中的哪个槽.等到时间轮指针指到这个槽,任务就被触发.

基本模型组成

  • tickMs(基本时间跨度):时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度(tickMs)。
  • wheelSize(时间单位个数):时间轮的时间格个数是固定的,可用(wheelSize)来表示,那么整个时间轮的总体时间跨度(interval)可以通过公式 tickMs × wheelSize计算得出。
  • currentTime(当前所处时间):时间轮还有一个表盘指针(currentTime),用来表示时间轮当前所处的时间,currentTime 是 tickMs 的整数倍。currentTime 可以将整个时间轮划分为到期部分和未到期部分,currentTime 当前指向的时间格也属于到期部分,表示刚好到期,需要处理此时间格所对应的 TimerTaskList 的所有任务。

单层时间轮
上面图例就是单层时间轮,这个时间轮的所能处理的最大周期是有限的,比如,一个具有10个slot的时间轮,wheel size = 10,每两个槽之间的间隔为1s,这个间隔称为tick,即最小的时间间隔,那么这个时间轮的跨度就是10*1 = 10s,也就是所支持能设置的最大周期为10s,如果一个任务每隔11秒执行一次.

同时,10s这个周期太短了,现在各种系统中不乏周期为成百上千秒的定时任务,且以1s为分割,颗粒太大了,秒级以下的定时任务无法被触发.

如果仅仅是个时间跨度为10s切以秒为tick的时间轮,是基本满足不了大部分场景的,为了满足需求,最简单快速的方法就是加大时间轮跨度来提升周期**,降低tick来提高精度,如果时间跨度提升为60s, tick改成10ms,就需要6000个槽来安插任务,这样就可以设置周期更长的任务,可以根据更精细的时间单位(10ms)来执行定时任务**

需求虽然得到满足,但也引发了一系列问题:

首先,轮询线程的遍历效率显著降低。当timescale数量增加而task数量较少时,例如仅有50个槽位存在task,却需要遍历6000个timescale,这与时间轮算法提升遍历效率的初衷相悖。

其次,存在内存空间浪费的问题。由于时间尺度密集而任务数量稀少,大部分时间尺度占用的内存空间实际上并未发挥应有作用。

更为严重的是,如果将时间轮跨度设置为1小时,整个时间轮将需要36000个单位的时间刻度(60x60x1000/100),这将导致时间轮算法的遍历线程面临更大的运行效率挑战。

由此可见,单层时间轮的性能上限较低,一旦对精度和时间跨度的要求提高,便难以实现预期目标。

多层时间轮
在这里插入图片描述
解析
第一层的时间轮 tickMs=1ms, wheelSize=20, interval=20ms。第二层的时间轮的 tickMs 为第一层时间轮的 interval,即为 20ms。每一层时间轮的 wheelSize 是固定的,都是 20,那么第二层的时间轮的总体时间跨度 interval 为 400ms。以此类推,这个 400ms 也是第三层的 tickMs 的大小,第三层的时间轮的总体时间跨度为 8000ms。

流程分析

  • 当到达时间格 2 时,如果此时有个定时为 350ms 的任务,显然第一层时间轮不能满足条件,所以就 时间轮升级 到第二层时间轮中,最终被插入到第二层时间轮中时间格 17 所对应的 TimerTaskList 中;
  • 如果此时又有一个定时为 450ms 的任务,那么显然第二层时间轮也无法满足条件,所以又升级到第三层时间轮中,最终被插入到第三层时间轮中时间格 1 的 TimerTaskList 中;
    注意到在到期时间在 [400ms,800ms) 区间的多个任务(比如446ms、455ms以及473ms的定时任务)都会被放入到第三层时间轮的时间格 1 中,时间格 1 对应的TimerTaskList的超时时间为400ms;
  • 随着时间的流逝,当次 TimerTaskList 到期之时,原本定时为 450ms 的任务还剩下 50ms 的时间,还不能执行这个任务的到期操作。这里就有一个 时间轮降级 的操作,会将这个剩余时间为 50ms 的定时任务重新提交到层级时间轮中,此时第一层时间轮的总体时间跨度不够,而第二层足够,所以该任务被放到第二层时间轮到期时间为 [40ms,60ms) 的时间格中;
  • 再经历了 40ms 之后,此时这个任务又被“察觉”到,不过还剩余 10ms,还是不能立即执行到期操作。所以还要再有一次时间轮的降级,此任务被添加到第一层时间轮到期时间为 [10ms,11ms) 的时间格中,之后再经历 10ms 后,此任务真正到期,最终执行相应的到期操作。

4 定时器设计

#ifndef _MARK_RBT_
#define _MARK_RBT_#include <stdio.h>
#include <stdint.h> // 整数
#include <unistd.h> // usleep
#include <stdlib.h> // malloc 注意需要强转
#include <stddef.h> //offsetof#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#include <sys/time.h>
#include <mach/task.h>
#include <mach/mach.h>
#else
#include <time.h>
#endif#include "rbtree.h"ngx_rbtree_t              timer;
static ngx_rbtree_node_t  sentinel;typedef struct timer_entry_s timer_entry_t;
typedef void (*timer_handler_pt)(timer_entry_t *ev);struct timer_entry_s {ngx_rbtree_node_t rbnode;timer_handler_pt handler;
};static uint32_t
current_time() {uint32_t t;
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)struct timespec ti;clock_gettime(CLOCK_MONOTONIC, &ti);t = (uint32_t)ti.tv_sec * 1000;t += ti.tv_nsec / 1000000;
#elsestruct timeval tv;gettimeofday(&tv, NULL);t = (uint32_t)tv.tv_sec * 1000;t += tv.tv_usec / 1000;
#endifreturn t;
}ngx_rbtree_t * init_timer() {ngx_rbtree_init(&timer, &sentinel, ngx_rbtree_insert_timer_value);return &timer;
}void add_timer(uint32_t msec, timer_handler_pt func) {timer_entry_t *te = malloc(sizeof(timer_entry_t));memset(te, 0, sizeof(timer_entry_t));te->handler = func;msec += current_time();printf("add_timer expire at msec = %u\n", msec);te->rbnode.key = msec;ngx_rbtree_insert(&timer, &te->rbnode);
}void del_timer(timer_entry_t *te) {ngx_rbtree_delete(&timer, &te->rbnode);free(te);
}int find_nearest_expire_timer() {ngx_rbtree_node_t  *node;if (timer.root == &sentinel) {return -1;}node = ngx_rbtree_min(timer.root, timer.sentinel);int diff = (int)node->key - (int)current_time();return diff > 0 ? diff : 0;
}void expire_timer() {timer_entry_t *te;ngx_rbtree_node_t *sentinel, *root, *node;sentinel = timer.sentinel;uint32_t now = current_time();for (;;) {root = timer.root;if (root == sentinel) break;node = ngx_rbtree_min(root, sentinel);if (node->key > now) break;printf("touch timer expire time=%u, now = %u\n", node->key, now);te = (timer_entry_t *) ((char *) node - offsetof(timer_entry_t, rbnode));te->handler(te);ngx_rbtree_delete(&timer, &te->rbnode);free(te);}
}

相关文章:

定时器设计

定时器设计的必要性 服务器中的定时器设计具有多方面的必要性&#xff0c;主要体现在以下几个关键方面&#xff1a; 任务调度与管理 定时任务执行&#xff1a;服务器常常需要执行一些定时性的任务&#xff0c;如定时备份数据、定时清理缓存、定时更新系统日志等。通过定时器可…...

Spring Boot整合Kafka实战指南:从环境搭建到消息处理全解析

一、环境准备 安装 Kafka 下载 Kafka&#xff1a;从 Apache Kafka 官网下载对应版本的 Kafka。 解压并启动 Kafka&#xff1a; # 启动 Zookeeper&#xff08;Kafka 依赖 Zookeeper&#xff09; bin/zookeeper-server-start.sh config/zookeeper.properties# 启动 Kafka bin/ka…...

(done) 补充:xv6 的一个用户程序 init 是怎么启动的 ?它如何启动第一个 bash ?

先看 main.c 从函数名来看&#xff0c;比较相关的就 userinit() 和 scheduler() #include "types.h" #include "param.h" #include "memlayout.h" #include "riscv.h" #include "defs.h"volatile static int started 0;//…...

AI 搜索引擎 MindSearch

背景 RAG是一种利用文档减少大模型的幻觉&#xff0c;AI搜索也是 AI 搜索引擎 MindSearch 是一个开源的 AI 搜索引擎框架&#xff0c;具有与 Perplexity.ai Pro 相同的性能。您可以轻松部署它来构建您自己的搜索引擎&#xff0c;可以使用闭源 LLM&#xff08;如 GPT、Claude…...

HTML简单语法标签(后续实操:云备份项目)

以下是一些 HTML 的简单语法标签及其功能介绍&#xff1a; 基本结构标签 <!DOCTYPE html>&#xff1a;声明文档类型为 HTML5<html>&#xff1a;HTML 文档的根标签<head>&#xff1a;包含文档元数据&#xff08;如标题、字符编码等&#xff09;<title>…...

CentOS 和 RHEL

CentOS 和 RHEL&#xff08;Red Hat Enterprise Linux&#xff09;关系非常紧密&#xff0c;简而言之&#xff1a; CentOS 最初是 RHEL 的免费、开源克隆版&#xff0c;几乎与 RHEL 二进制兼容。 CentOS 原是 RHEL 的“免费双胞胎”&#xff0c;但已被放弃&#xff0c;现在推荐…...

java----------->代理模式

目录 什么是代理模式&#xff1f; 为什么会有代理模式&#xff1f; 怎么写代理模式&#xff1f; 实现代理模式总共需要三步&#xff1a; 什么是代理模式&#xff1f; 代理模式&#xff1a;给目标对象提供一个代理对象&#xff0c;并且由代理对象控制目标对象的引用 代理就是…...

Wpf学习片段

IRegionManager 和IContainerExtension IRegionManager 是 Prism 框架中用于管理 UI 区域&#xff08;Regions&#xff09;的核心接口&#xff0c;它实现了模块化应用中视图&#xff08;Views&#xff09;的动态加载、导航和生命周期管理。 IContainerExtension 是依赖注入&…...

智能手表测试用例文档

智能手表测试用例文档 产品名称&#xff1a;智能手表 A1 版本号&#xff1a;FW v1.0.0 测试负责人&#xff1a;[填写] 编写时间&#xff1a;2025-xx-xx 文档状态&#xff1a;初次版本 &#x1f4c1; 测试用例结构说明 字段描述用例编号测试用例唯一编号&#xff0c;如 TC-FUN…...

密码学--希尔密码

一、实验目的 1、通过实现简单的古典密码算法&#xff0c;理解密码学的相关概念 2、理解明文、密文、加密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。 二、实验内容 1、题目内容描述 ①定义分组字符长度 ②随机生成加密密钥&#xff0c;并验证密钥的可行性 …...

配置Hadoop集群-集群配置

以下是 Hadoop 集群的核心配置步骤&#xff0c;基于之前的免密登录和文件同步基础&#xff0c;完成 Hadoop 分布式环境的搭建&#xff1a; 1. 集群规划 假设集群包含 3 个节点&#xff1a; master&#xff1a;NameNode、ResourceManagerslave1&#xff1a;DataNode、NodeMana…...

第三方软件测评中心分享:软件功能测试类型和测试工具

在数字化时代&#xff0c;软件测试已成为确保产品质量的重要环节。功能测试作为软件测试中的核心部分&#xff0c;关注于软件产品是否按预期功能正常运作。 软件功能测试可以按不同的方式进行分类&#xff0c;主要包括以下几种类型&#xff1a;   1.正功能测试&#xff1a;验…...

Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互

Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互 Profibus DP主站转Modbus RTU/TCP&#xff08;XD-MDPBm20&#xff09;网关在Profibus总线侧实现主站功能&#xff0c;在Modbus串口侧实现从站功能。可将ProfibusDP协议的设备&#xff08;如&#xff1a;海…...

多视角系统,视角之间的切换,输入操作。无人机Pawn视角的实现

一.创建自己的PlayerController。它相当于是灵魂&#xff0c;穿梭在不同Pawn之间。也即是切换视角。不同输入的响应也写在这里。这样即使&#xff0c;都有鼠标操作&#xff0c;也能区分。避免了代码的重复耦合。也可以叫做视角系统。 class LZJGAMEMODE_API ALZJPlayerControl…...

[学习]RTKLib详解:ionex.c、options.c与preceph.c

RTKLib详解&#xff1a;ionex.c、options.c与preceph.c 本文是 RTKLlib详解 系列文章的一篇&#xff0c;目前该系列文章还在持续总结写作中&#xff0c;以发表的如下&#xff0c;有兴趣的可以翻阅。 [学习] RTKlib详解&#xff1a;功能、工具与源码结构解析 [学习]RTKLib详解&…...

【Linux笔记】——进程信号的保存

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;【Linux笔记】——进程信号的产生 &#x1f516;流水不争&#xff0c;争的是滔滔不 一、信号的相关概念二、信…...

教育机构教务管理系统哪个好?

在当今教育培训行业快速发展的背景下&#xff0c;一个高效、专业的教务管理系统已成为教育机构提升运营效率、优化教学质量的关键工具。本文将深入分析爱耕云教务管理系统的核心优势&#xff0c;通过具体功能解析和代码示例展示其技术实现方式&#xff0c;并对比市场上其他主流…...

ZYNQ笔记(二十):Clocking Wizard 动态配置

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 任务&#xff1a;ZYNQ PS端 通过 AXI4Lite 接口配置 Clocking Wizard IP核输出时钟频率 目录 一、介绍 二、寄存器定义 三、配置 四、PS端代码 一、介绍 Xilinx 的 Clock Wizard IP核 用于在 FPGA 中生成和管理…...

电商平台一站式网络安全架构设计指南

摘要&#xff1a;据 Gartner 统计&#xff0c;采用一体化安全方案的电商企业数据泄露成本降低 67%。本文从攻击链分析到防御体系构建&#xff0c;详解如何实现网络层、应用层、数据层的协同防护。 一、电商安全威胁全景图&#xff08;2024 攻击态势&#xff09; 1.1 攻击者完…...

烟花爆竹储存需要注意哪些问题

烟花爆竹储存需要注意哪些问题 烟花爆竹作为易燃易爆物品&#xff0c;其储存安全至关重要。不当的储存方式不仅可能导致产品失效&#xff0c;更可能引发火灾、爆炸等严重事故。以下是烟花爆竹储存需要注意的几个关键问题&#xff1a; 一、储存场所选择 必须选择专用仓库储存…...

C++11详解

文章目录 前言一、列表初始化1.1 {} 初始化1.2 initializer_list 类型 三、声明3.1 auto3.2 decltype 四、右值引用和移动语义4.1 左值引用和右值引用4.2 移动语义 五、可变参数模板六、lambda表达式各部分详细解释示例代码代码解释 七、包装器八、bind注意事项 前言 C11在系统…...

VLM-RL:用于安全自动驾驶的统一视觉语言模型和强化学习框架——论文阅读

《VLM-RL: A Unified Vision Language Models and Reinforcement Learning Framework for Safe Autonomous Driving》2024年12月发表&#xff0c;来自Wisconsin Madison分校和Purdue大学的论文。 近年来&#xff0c;基于强化学习&#xff08;RL&#xff09;的学习驾驶策略的方法…...

新手安装java所有工具(jdk、idea,Maven,数据库)

新手安装JAVA工具 介绍JDK11IDEA 2025.1Maven数据库&#xff08;Navicat Premium Lite&#xff09; 介绍 涉及安装JAVA所需的各种工具 JDK&#xff08;以JDK11为例&#xff09;IDEA&#xff08;以2025.1为例&#xff09;Maven&#xff08;以3.8.8为例&#xff09;数据库&…...

hive在配置文件中添加了hive.metastore.uris之后进入hive输入命令报错

在hive-site.xml文件中加入配置hive.metastore.uris启动hive后报错 <property><name>hive.metastore.uris</name><value>thrift://node154:9083</value></property> 加完属性就需要手动启动metastore服务&#xff0c;因为不使用 Zookeepe…...

Hive原理

Hive 是构建在 Hadoop 上的数据仓库工具,其核心原理是通过类 SQL 语言(HiveQL)将结构化数据查询转换为分布式计算任务(如 MapReduce、Tez、Spark),并利用 HDFS 存储数据。以下是 Hive 的核心原理和架构: 1. 核心设计思想‌ ‌数据仓库抽象‌:将 HDFS 上的文件抽象为‌…...

cursor 出现 unauthorized request

文档出自&#xff1a;https://www.kdocs.cn/l/csE3iuSauHoS...

uniapp|商品列表加入购物车实现抛物线动画效果、上下左右抛入、多端兼容(H5、APP、微信小程序)

以uniapp框架为基础,详细解析商品列表加入购物车抛物线动画的实现方案。通过动态获取商品点击位置与购物车坐标,结合CSS过渡动画模拟抛物线轨迹,实现从商品图到购物车图标的动态效果。 目录 核心实现原理坐标动态计算抛物线轨迹模拟​动画元素控制代码实现详解模板层设计脚本…...

点下4个Winform UI开源控件库

从零学习构建一个完整的系统 今天一起来盘点下4个Winform UI开源控件库&#xff0c;有.Net Framework&#xff0c;也有.Net Core。 1、支持.Net 7的开源UI组件框架 项目简介 这是一个基于.Net Framework、.Net 6开发的&#xff0c;WinForm开源UI框架&#xff0c;框架包含常…...

【AI】mcp server本质就是一个接口服务么

以下为元宝的回答&#xff1a; 你的理解非常准确&#xff01;​​MCP Server​​本质上是一个接口服务&#xff0c;但其设计目标、交互逻辑和使用场景与传统后端接口存在显著差异。以下是两者的对比分析&#xff1a; ​​1. 核心定位差异​​ ​​维度​​​​MCP Server​​…...

chalrs正常使用一段时间后开启代理访问网页 显示“不是私密链接”解决办法

chalrs正常使用一段时间后开启代理访问网页 显示“不是私密链接”解决办法 背景&#xff1a; charles用了好长时间了&#xff0c;最近发现打开charles有些软件无法上网&#xff0c;浏览器访问网页提示“您的连接不是私密链接”&#xff0c;按照网上的教程重装了几次证书&#x…...

如何通过DNS解析实现负载均衡?

在当今的互联网时代&#xff0c;随着网络应用的飞速发展&#xff0c;网站和各类在线服务面临着海量的用户请求。为了保障服务的高可用性和高性能&#xff0c;负载均衡技术应运而生。DNS&#xff08;域名系统&#xff09;负载均衡作为其中一种重要的实现方式&#xff0c;凭借其简…...

uni-app微信小程序登录流程详解

文章目录 uni-app微信小程序登录流程实战详解微信小程序登录流程概述1. 获取登录凭证&#xff08;code&#xff09;2. 发送登录请求3. 保存登录态4. 登录状态管理5. 应用登录状态请求拦截器中添加 token自动登录页面路由守卫 使用 Vuex 集中管理登录状态登录组件示例登录流程最…...

基于LVS和Keepalived实现高可用负载均衡架构

目录 一、资源清单 二、修改主机名 三、配置调度器 四、配置Web节点服务器&#xff08;web1、web2&#xff09; 五、测试负载均衡 六、测试LVSKeepalived高可用群集 一、资源清单 主机 操作系统 IP地址 lb01 OpenEuler24.03 192.168.16.142 lb02 OpenEuler24.03 …...

微信小程序仿淘宝拍照/照片点位识图、点位裁剪生图、图片裁剪组件、图片点位框选、裁剪生成图片,canvasToImg

实现效果 效果&#xff1a; 1.微信小程序仿淘宝拍照/照片点位识图、根据点位裁剪生图、图片可裁剪、图片高度可控 2.识别点位自动生成标准构图方案&#xff0c;支持手动微调实现像素级精准裁剪 3.可以根据接口识别的点位信息实现拍照/相册图片特征点自动识别并裁剪 实现步骤 …...

EnumUtils:你的枚举“变形金刚“——让枚举操作不再手工作业

各位枚举操控师们好&#xff01;今天要介绍的是Apache Commons Lang3中的EnumUtils工具类。这个工具就像枚举界的"瑞士军刀"&#xff0c;能让你的枚举操作从石器时代直接跃迁到星际文明&#xff01; 一、为什么需要EnumUtils&#xff1f; 手动操作枚举就像&#xf…...

在Taro中开发一个跨端Svg组件,同时支持小程序、H5、React Native

Taro系列中一直没有跨端的绘图工具&#xff0c;小程序端支持canvas但是不支持svg&#xff0c;RN端有 react-native-svg 支持svg&#xff0c;但是没有很好原生的canvas插件&#xff0c;社区的canvas都是基于WebView实现的&#xff0c;或者skia&#xff0c;这个插件的书写方式和c…...

大型视频学习平台项目问题解决笔记

一 数据库大量读操作导致数据库压力过大的解决方案 1. 优化SQL语句 2. 缓存 二 数据库大量写操作导致数据库压力过大的解决方案 1. 优化SQL语句 2. 改同步写为异步写——解决复杂事务的高并发写 3. 合并写请求——解决简单事务的高并发写&#xff08;额外实现一个异步操作来…...

day18-数据结构引言

一、 概述 数据结构&#xff1a;相互之间存在一种或多种特定关系的数据元素的集合。 1.1 特定关系&#xff1a; 1. 逻辑结构 2.物理结构&#xff08;在内存当中的存储关系&#xff09; 逻辑结构物理结构集合&#xff0c;所有数据在同一个集合中&#xff0c;关系平等顺…...

Android音频解码中的时钟同步问题:原理、挑战与解决方案

一、为什么音频同步如此重要&#xff1f; 在多媒体播放系统中&#xff0c;音频同步问题直接影响用户体验。根据行业研究数据&#xff1a; • 15ms以上的同步偏差&#xff1a;53%的用户能感知到音画不同步 • 超过100ms的偏差&#xff1a;会导致明显的"口型对不上"现…...

深入浅出 iOS 对象模型:isa 指针 与 Swift Metadata

在 iOS 开发中&#xff0c;我们经常听到两个看似神秘的词&#xff1a;isa 指针 和 Metadata。这两个概念分别源自 Objective-C 和 Swift 的对象系统&#xff0c;是我们理解底层运行机制、优化性能乃至调试疑难问题的关键。今天我们就来聊一聊&#xff0c;它们到底是什么&#x…...

ARMV8 RK3399 u-boot TPL启动流程分析 --crt0.S

上一篇介绍到start.S 最后一个指令是跳转到_main, 接下来分析 __main 都做了什么 arch/arm/lib/crt0.S __main 注释写的很详细&#xff0c;主要分为5步 1. 准备board_init_f的运行环境 2. 跳转到board_init_f 3. 设置broad_init_f 申请的stack 和 GD 4. 完整u-boot 执行re…...

Lynx-字节跳动跨平台框架多端兼容Android, iOS, Web 原生渲染

介绍 字节跳动近期开源的跨平台框架Lynx被视为一项重要的技术创新。相较于市场上已有的解决方案如React Native (RN) 和Flutter&#xff0c;Lynx具有独特的特性。 首先&#xff0c;Lynx采用轻量级JavaScript逻辑设计&#xff0c;DOM节点构建完全置于Native层&#xff0c;确保U…...

手机换地方ip地址会变化吗?深入解析

在移动互联网时代&#xff0c;我们经常带着手机穿梭于不同地点&#xff0c;无论是出差旅行还是日常通勤。许多用户都好奇&#xff1a;当手机更换使用地点时&#xff0c;IP地址会随之改变吗&#xff1f;本文将深入解析手机IP地址的变化机制&#xff0c;帮助您全面了解这一常见但…...

Linux——数据库备份与恢复

一&#xff0c;Mysql数据库备份概述 1&#xff0c;数据库备份的重要性 数据灾难恢复&#xff1a;数据库可能会因为各种原因出现故障&#xff0c;如硬件故障、软件错误、误操作、病毒攻击、自然灾害等。这些情况都可能导致数据丢失或损坏。如果有定期的备份&#xff0c;就可以…...

矩阵键盘模块

目录 1.矩阵键盘介绍 2.扫描的概念 数码管扫描&#xff08;输出扫描&#xff09; 矩阵键盘扫描&#xff08;输入扫描&#xff09; 矩阵按键采用逐行扫描&#xff1a; 3.矩阵键盘代码 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a; 第四步&#xff1…...

连接词化归律详解

1. 连接词化归律的基本概念 连接词化归律(也称为归结原理)是数理逻辑中用于简化逻辑表达式的重要方法&#xff0c;它允许我们将复杂的逻辑表达式转化为更简单的等价形式&#xff0c;特别是转化为合取范式(CNF)或析取范式(DNF)。 核心思想 连接词化归律基于一系列逻辑等价关系…...

Ubuntu 18.04 iso文件下载

参考&#xff1a;https://blog.csdn.net/Li060703/article/details/106075597 Rufus 官网&#xff1a; https://rufus.ie/zh/ 镜像下载地址 阿里云镜像站&#xff1a;https://mirrors.aliyun.com/ubuntu-releases/18.04/ 网易镜像&#xff1a;http://mirrors.163.com/ub…...

【C#】ToArray的使用

在 C# 中&#xff0c;ToArray 方法通常用于将实现了 IEnumerable<T> 接口的集合&#xff08;如 List<T>&#xff09;转换为数组。这个方法是 LINQ 提供的一个扩展方法&#xff0c;位于 System.Linq 命名空间中。因此&#xff0c;在使用 ToArray 方法之前&#xff0…...

学习日志03 java

最近有点懈怠了&#xff0c;多多实践&#xff0c;多敲代码&#xff0c;多多专注&#xff01; 1 ArithmeticException ArithmeticException 是 Java 中的一个异常类&#xff0c;它继承自 RuntimeException&#xff0c;用于表示在算术运算中出现的错误。这个异常通常在以下情况…...

数据库故障排查指南

对于项目研发来讲&#xff0c;数据库是必不可少的一个重要环节&#xff0c;本文详细总结了项目研发中数据库故障问题排查指南&#xff0c;希望会对大家有所帮助。 数据库连接问题 检查数据库服务是否正常运行&#xff0c;确认网络连接是否畅通&#xff0c;验证数据库配置文件…...