ZLMediaKit 源码分析——[4] ZLToolKit 中EventPoller之异步任务处理
系列文章目录
第一篇 基于SRS 的 WebRTC 环境搭建
第二篇 基于SRS 实现RTSP接入与WebRTC播放
第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建
第四篇 WebRTC学习一:获取音频和视频设备
第五篇 WebRTC学习二:WebRTC音视频数据采集
第六篇 WebRTC学习三:WebRTC音视频约束
第七篇 WebRTC学习四:WebRTC常规视觉滤镜
第八篇 WebRTC学习五:从视频中提取图片
第九篇 WebRTC学习六:MediaStream 常用API介绍
第十篇 WebRTC学习七:WebRTC 中 STUN 协议详解
ZLMediaKit源码分析——[1] 开篇:基础库 ZLToolKit 之 onceToken 源码分析
ZLMediaKit 源码分析——[2] 从 ZLToolKit 代码看 CPU 亲和性设计
ZLMediaKit 源码分析——[3] ZLToolKit 中EventPoller之网络事件处理
ZLMediaKit 源码分析——[4] ZLToolKit 中EventPoller之异步任务处理
文章目录
- 系列文章目录
- 前言
- 一、异步任务处理原理
- 二、类图
- 三、源码分析
- 3.1添加管道监听事件
- 3.2 内部管道事件onPipeEvent
- 3.3 异步任务调度runLoop
- 四、异步事件接口
- 4.1 异步执行任务 async_l
- 4.2 异步执行任务 async
- 4.3 异步执行任务 async_first
- 五、使用方法
- 5.1 测试用例
- 输出如下: 
- 总结
前言
在前面的文章中,我们详细剖析了 ZLToolKit 里 EventPoller 的网络事件处理机制。当深入研究 EventPoller 时,会发现它不仅负责网络事件的管理,还承担着异步任务处理的重要职责。这和 live555 里的设计类似,在事件循环中除了处理网络事件,也会执行异步任务和延时队列。今天,我们就来深入探讨一下 ZLToolKit 中 EventPoller 的异步任务处理机制。
一、异步任务处理原理
在 EventPoller 中,异步任务处理的核心在于将任务的执行与主线程分离,避免阻塞主线程的执行。当用户提交一个异步任务时,EventPoller 会判断是否适合同步执行,如果不适合同步执行,则将该任务添加到一个任务队列中。在 EventPoller 的事件循环中,会不断检查任务队列是否有任务需要执行,如果有则依次取出并执行这些任务。
具体来说,EventPoller 采用了生产者 - 消费者模型。用户代码作为生产者,将异步任务添加到任务队列;而 EventPoller 的事件循环则作为消费者,从任务队列中取出任务并执行。这种模型的好处是可以将耗时的任务异步执行,不影响主线程的正常运行,从而提高系统的并发处理能力。
其核心类为 EventPoller,关键函数是 runLoop ,异步事件处理中关键的数据结构为_list_task,用户接口为async和async_first 。
二、类图
这里对类图进行了简化,只抽取了和异步任务有关的类,即本文可能会讨论的地方。
三、源码分析
3.1添加管道监听事件
再看addEvent函数
int EventPoller::addEvent(int fd, int event, PollEventCB cb) {// 时间检查TimeTicker();// 回调函数检查if (!cb) {WarnL << "PollEventCB is empty";return -1;}// 当前线程检查,// 如果是当前线程:根据不同的操作系统平台选择不同的事件通知机制来添加事件监听。if (isCurrentThread()) {
#if defined(HAS_EPOLL)struct epoll_event ev = {0};ev.events = toEpoll(event) ;ev.data.fd = fd;int ret = epoll_ctl(_event_fd, EPOLL_CTL_ADD, fd, &ev);if (ret != -1) {_event_map.emplace(fd, std::make_shared<PollEventCB>(std::move(cb)));}return ret;
#elif defined(HAS_KQUEUE)
#else
#endif}// 如果不是当前线程,发起异步操作:// 使用 async 函数异步调用 addEvent 函数,将事件添加操作放到合适的线程中执行。async([this, fd, event, cb]() mutable {addEvent(fd, event, std::move(cb));});return 0;
}
再看函数后面非当前线程处理这里,如果不是当前线程,这里会调用async函数,将会再次addEvent函数,直到是当前线程,添加进_event_map中,对这里的理解很关键,结合下面这个函数,可以带着几个问题,addEvent事件会调用多次吗?onPipeEvent是什么时候调用的?onPipeEvent会调用多次吗?理解了这里,就基本上理解了ZLMediaKit中异步任务的关键。
void EventPoller::addEventPipe() {SockUtil::setNoBlocked(_pipe.readFD());SockUtil::setNoBlocked(_pipe.writeFD());// 添加内部管道事件if (addEvent(_pipe.readFD(), EventPoller::Event_Read, [this](int event) { onPipeEvent(); }) == -1) {throw std::runtime_error("Add pipe fd to poller failed");}
}
EventPoller::addEventPipe() 函数的主要功能是对内部管道的读写文件描述符进行非阻塞设置,并将管道的读文件描述符添加到事件轮询器中,以便监听管道的可读事件。当管道有可读事件发生时,会调用 onPipeEvent() 函数进行相应处理。
3.2 内部管道事件onPipeEvent
inline void EventPoller::onPipeEvent(bool flush) {char buf[1024];int err = 0;if (!flush) {for (;;) {if ((err = _pipe.read(buf, sizeof(buf))) > 0) {// 读到管道数据,继续读,直到读空为止continue;}if (err == 0 || get_uv_error(true) != UV_EAGAIN) {// 收到eof或非EAGAIN(无更多数据)错误,说明管道无效了,重新打开管道ErrorL << "Invalid pipe fd of event poller, reopen it";delEvent(_pipe.readFD());_pipe.reOpen();addEventPipe();}break;}}decltype(_list_task) _list_swap;{lock_guard<mutex> lck(_mtx_task);_list_swap.swap(_list_task);}_list_swap.for_each([&](const Task::Ptr &task) {try {(*task)();} catch (ExitException &) {_exit_flag = true;} catch (std::exception &ex) {ErrorL << "Exception occurred when do async task: " << ex.what();}});
}
EventPoller::onPipeEvent 函数的核心功能是处理管道事件。它会根据传入的 flush 参数决定是否清空管道,在管道出现异常时进行重新打开操作,同时会执行之前存储在任务列表中的异步任务。
函数原型void onPipeEvent(bool flush = false);参数flush 默认值为false,整个代码中只有两处调用onPipeEvent,一处为1中添加管道监听事件中addEventPipe()中,传参为false。
第二处为析构函数中,传参为true。
EventPoller::~EventPoller() {//...其它代码onPipeEvent(true);InfoL << getThreadName();
}
3.3 异步任务调度runLoop
EventPoller::runLoop 函数是 EventPoller 类的核心函数,它实现了事件循环的逻辑,不断地监听网络套接字和内部管道的事件并进行处理。
void EventPoller::runLoop(bool blocked, bool ref_self) {if (blocked) {if (ref_self) {s_current_poller = shared_from_this();}_sem_run_started.post();_exit_flag = false;uint64_t minDelay;
#if defined(HAS_EPOLL)struct epoll_event events[EPOLL_SIZE];while (!_exit_flag) {minDelay = getMinDelay();startSleep();//用于统计当前线程负载情况int ret = epoll_wait(_event_fd, events, EPOLL_SIZE, minDelay ? minDelay : -1);sleepWakeUp();//用于统计当前线程负载情况if (ret <= 0) {//超时或被打断continue;}_event_cache_expired.clear();for (int i = 0; i < ret; ++i) {struct epoll_event &ev = events[i];int fd = ev.data.fd;if (_event_cache_expired.count(fd)) {//event cache refreshcontinue;}auto it = _event_map.find(fd);if (it == _event_map.end()) {epoll_ctl(_event_fd, EPOLL_CTL_DEL, fd, nullptr);continue;}auto cb = it->second;try {(*cb)(toPoller(ev.events)); // 将epoll事件类型转换回自定事件类型} catch (std::exception &ex) {ErrorL << "Exception occurred when do event task: " << ex.what();}}}
#elif defined(HAS_KQUEUE)// ... 其他系统的处理代码
#else// ... 其他系统的处理代码
#endif //HAS_EPOLL} else {_loop_thread = new thread(&EventPoller::runLoop, this, true, ref_self);_sem_run_started.wait();}
}
这个函数的处理逻辑在上篇博文中已经详细介绍了,这里与网络事件区别是监听的是无名管道读端描述符,addEventPipe中通过监听addEvent(_pipe.readFD(), EventPoller::Event_Read, [this](int event) { onPipeEvent(); })加入的_pipe.readFD()读端管道描述符,这里执行的cb即为[this](int event) { onPipeEvent(); }。
四、异步事件接口
4.1 异步执行任务 async_l
源码如下:
Task::Ptr EventPoller::async_l(TaskIn task, bool may_sync, bool first) {TimeTicker();if (may_sync && isCurrentThread()) {task();return nullptr;}auto ret = std::make_shared<Task>(std::move(task));{lock_guard<mutex> lck(_mtx_task);if (first) {_list_task.emplace_front(ret);} else {_list_task.emplace_back(ret);}}//写数据到管道,唤醒主线程_pipe.write("", 1);return ret;
}
EventPoller::async_l 函数的主要功能是根据传入的参数决定是同步执行任务还是异步执行任务。如果可以同步执行,则直接执行任务;否则,将任务封装到 Task 对象中,并插入到任务列表中,然后通过向管道写入数据唤醒主线程来处理任务。最后返回异步任务的智能指针。从这里也能看出保存异步任务列表的关键的数据结构是_list_task,原型为ListTask::Ptr _list_task。
4.2 异步执行任务 async
对async_l的封装,将任务加到队尾执行
Task::Ptr EventPoller::async(TaskIn task, bool may_sync) {return async_l(std::move(task), may_sync, false);
}
4.3 异步执行任务 async_first
对async_l的封装,将任务加到队列头部,表示插入优先级高的任务
Task::Ptr EventPoller::async_first(TaskIn task, bool may_sync) {return async_l(std::move(task), may_sync, true);
}
五、使用方法
5.1 测试用例
#include "EventPoller/EventPoller.h"
#include <iostream>
using namespace toolkit;int main()
{for (int i = 0; i < 10; i++) {EventPollerPool::Instance().getPoller()->async([i]{ std::cout << "hello task " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));});}std::this_thread::sleep_for(std::chrono::seconds(10));return 0;
}
输出如下:

总结
本文深入剖析了 ZLToolKit 中 EventPoller 的异步任务处理机制。详细讲解了其核心原理,即采用生产者 - 消费者模型将任务执行与主线程分离,提高系统并发处理能力。通过对关键类 EventPoller、函数 runLoop、数据结构 _list_task 以及用户接口 async 和 async_first 的分析,展示了异步任务处理的实现方式。
在源码层面,addEvent 函数会根据线程情况决定同步或异步添加事件监听;addEventPipe 函数对内部管道进行非阻塞设置并监听读事件;onPipeEvent 函数处理管道事件并执行异步任务;runLoop 函数实现事件循环,监听管道读端描述符。同时,还介绍了 async_l、async 和 async_first 等异步事件接口的功能,最后还给了一个简单的测试用例。
通过对这些机制的理解,开发者能够更好地利用 ZLToolKit 进行网络编程,实现高效的异步任务处理。后续可能还会对相关内容进行进一步分析,敬请期待。
相关文章:
ZLMediaKit 源码分析——[4] ZLToolKit 中EventPoller之异步任务处理
系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC学习一:获取音频和视频设备 第五篇 WebRTC学习二:WebRTC音视频数据采集 第六篇 WebRTC学习三…...
基于 DeepSeek 与天地图搭建创新地理信息应用
一、技术背景 DeepSeek 是由国内公司研发的一款具有强大参数规模与性能的大语言模型,它能够处理复杂的自然语言指令,提供丰富的分析与建议。天地图则是国家地理信息公共服务平台,提供权威、丰富的地理信息数据,涵盖卫星影像、矢量…...
python函数装饰器
python函数装饰器 声明:博主并没有系统学习过python语言,在实际项目中遇到关于python不懂的语法,这里仅作为个人学习积累笔记 1.1 python函数相关基础 深入了解python函数装饰器移步:Python 函数装饰器 下面的笔记来源于上述链接…...
AI战略群与星际之门:软银AI投资版图计划深度解析
一、星际之门:万亿美元级 AI 基础设施革命 1.1 项目背景与战略定位 在 AI 技术迅猛发展的今天,算力已成为推动其前进的核心动力。软银联合 OpenAI、甲骨文、英伟达、微软、arm推出的 “星际之门”(Stargate)计划,无疑是 AI 领域的一颗重磅炸弹。作为 AI 领域史上最大单笔…...
Modbus TCP转profibusDP网关接防撞雷达快速配置
Modbus TCP转profibusDP网关接防撞雷达快速配置 在工业自动化领域中,不同的设备可能使用不同的通信协议。当需要将使用 ModbusTCP 协议的防撞雷达连接到ProfibusDP网络时,需要使用协议转换器来实现协议的转换。 本文将详细介绍如何通过ModbusTCP转Profi…...
O(1) 时间复杂度数据设计题
0x00 preface 所谓 O ( 1 ) O(1) O(1) A P I API API 设计,并不是说,时间复杂度必须是**“总是”常数级别的。 对于一个操作来说,如果他偶尔是 O ( N ) O(N) O(N) 的,大部分时间都是 O ( 1 ) O(1) O(1) 的,并且&a…...
基于Spring AI与Ollama构建本地DeepSeek对话机器人
1、安装ollama: 打开Ollama下载官网,根据自己的操作系统下载相应版本的安装文件。 由于Ollama默认安装在C盘,而Ollama和模型文件都非常大,如果安装在C盘非常占用系统空间,可以使用下面的方法将Ollama安装到指定为止 …...
边缘计算赋能淘宝API:分布式节点缓存降低高并发延迟
以下是关于 “边缘计算赋能淘宝 API:分布式节点缓存降低高并发延迟” 的相关内容介绍: 背景 淘宝作为大型电商平台,每天面临海量的用户访问和高并发请求。在传统的集中式计算架构下,处理如此大规模的请求容易导致网络延迟、响应速…...
Keepalived+LVS+nginx高可用架构
注明:所有软件已经下载好,防火墙和SELinux已经全部关闭 一.搭建NFS 1.服务端 1.创建文件 [rootnfs ~]# mkdir -p /nfs/data 2、修改权限 [rootnfs ~]# chmod orw /nfs/data 3、写配置文件 [rootnfs ~]# cat /etc/exports /nfs/data 192.168.111.118(r…...
CMake学习--如何在CMake中编译静态库、动态库并在主程序中调用
目录 一、背景知识二、使用方法(一)编译静态库(二)编译动态库(三)在主程序中调用库 三、总结 一、背景知识 在C/C开发中,库(Library)是预先编译好的代码集合,…...
技术回顾day3
1.获取文件信息、获取视频信息 走的都是同一个方法:baseController里面的getFile。 在getFile方法里面进行判断文件的类型,判断是不是m3u8类型或者ts类型做一些额外的处理。 获取信息底层就是读取文件,然后写入response的OutputStream ou…...
【dp + 裴蜀定理】P8646 [蓝桥杯 2017 省 AB] 包子凑数 题解
P8646 [蓝桥杯 2017 省 AB] 包子凑数 题解 题目传送门 P8646 [蓝桥杯 2017 省 AB] 包子凑数 一、题目描述 小明发现包子铺有N种蒸笼,每种能放A_i个包子(无限供应)。问有多少个正整数X无法被这些蒸笼数量的组合表示出来。若无限多个则输出…...
在HarmonyOS NEXT 开发中,如何指定一个号码,拉起系统拨号页面
大家好,我是 V 哥。 《鸿蒙 HarmonyOS 开发之路 卷1 ArkTS篇》已经出版上市了哈,有需要的朋友可以关注一下,卷2应用开发篇也马上要出版了,V 哥正在紧锣密鼓的写鸿蒙开发实战卷3的教材,卷3主要以项目实战为主࿰…...
网络华为HCIA+HCIP 策略路由,双点双向
目录 路由策略,策略路由 策略路由优势 策略路由分类 接口策略路由 双点双向 双点双向路由引入特点: 联系 路由回灌和环路问题 路由策略,策略路由 路由策略:是对路由条目进行控制,通过控制路由条目影响报文的转发路径,即路…...
探索Doris:日志分析的新宠,是否能取代老牌ES?
在大数据时代,日志存储与分析对于企业的运营和决策起着至关重要的作用。Elasticsearch(简称 ES)作为一款广泛应用的开源分布式搜索和分析引擎,长期以来在日志管理领域占据着举足轻重的地位。然而,随着技术的不断发展&a…...
常见电源模块设计
目录 1. 5V电源模块 2. 3.3V电源模块 3. 1.9V电源模块 4. 220V转12V电源模块 1. 5V电源模块 参考电路 电路说明: 这个电路采用的是稳压芯片78L05,我是用的12V的电源模块转成为5V,为后续的供电。 2. 3.3V电源模块 参考电路: 电路说明…...
虚幻引擎控制角色跟随移动方向旋转的方法
在UE5中,要控制角色随移动方向旋转,可以使用蓝图和C两种方式来实现。 使用蓝图 1、选中角色移动组件,勾选将旋转朝向运动。 2、选中当前角色类 取消勾选使用控制器旋转的几个选项 3、这时,摄像机会跟着角色一起旋转。如果不希望…...
Oracle 23ai Vector Search 系列之3 集成嵌入生成模型(Embedding Model)到数据库示例,以及常见错误
文章目录 Oracle 23ai Vector Search 系列之3 集成嵌入生成模型(Embedding Model)到数据库示例,以及常见错误使用安装了Oracle 23ai 的虚拟机(Oracle Database 23ai Free VirtualBox Appliance)1.下载[Oracle VM Virtu…...
RISC-V debug专栏2 --- Debug Module(DM)
Debug Module(DM)的核心功能 DM 就像一个翻译官,负责把调试器的抽象指令(比如 “暂停处理器”)转换成硬件能听懂的具体操作。它必须实现以下基本功能: 必要功能(必须实现)ÿ…...
LLM 分词器Tokenizer 如何从 0 到 1 训练出来
写在前面 大型语言模型(LLM)处理的是人类的自然语言,但计算机本质上只能理解数字。Tokenizer(分词器) 就是架在自然语言和计算机数字表示之间的一座至关重要的桥梁。它负责将我们输入的文本字符串分解成模型能够理解的最小单元——Token,并将这些 Token 转换成对应的数字…...
蓝桥杯冲刺:一维前缀和
系列文章目录 蓝桥杯系列:一维前缀和 文章目录 系列文章目录前言一、暴力的写法:二、一维前缀和的模板: 具体实现: 三、具体例题:求和 1.题目参考:2.以下是具体代码实现: 总结 前言 上次我介绍…...
光学关键尺寸量测设备市场报告:2024年全球市场销售额达到了14.75亿美元
一、引言 光学关键尺寸量测设备作为半导体制造、精密加工等领域的核心工具,其重要性不言而喻。随着科技的飞速发展,这些设备在提升产品精度、缩短研发周期、降低生产成本等方面发挥着越来越关键的作用。本报告旨在深入分析光学关键尺寸量测设备的技术特…...
链表的操作-反转链表
链表 160相交链表 代码 class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* h1headA;ListNode* h2headB;while(h1&&h2){if(h1!h2){h1h1->next;h2h2->next;}else{return h1;}}if(h1nullptr){h1headB;}else{h…...
2025 年浙江危化品经营单位考试攻略分享
浙江的考试由省应急管理部门主导。理论考试突出危化品在电商、物流等新兴业态下的安全管理知识,这与浙江发达的电商产业紧密相关。对危险化学品的环境危害及防治知识考查细致。实际操作考核模拟杭州、宁波等地危化品仓储物流中心的作业情况。 报名材料准备齐全后…...
python使用cookie、session、selenium实现网站登录(爬取信息)
一、使用cookie 这段代码演示了如何使用Python的urllib和http.cookiejar模块来实现网站的模拟登录,并在登录后访问需要认证的页面。 # 导入必要的库 import requests from urllib import request, parse# 1. 导入http.cookiejar模块中的CookieJar类,用…...
STM32开发板上生成PWM正弦波
在STM32开发板上生成正弦波通常需要结合定时器(TIM)、数模转换器(DAC)或脉宽调制(PWM)以及时钟系统的配置。以下是分步指南: 方法1:使用DAC 定时器(推荐) 步…...
Spring Boot 实现文件秒传功能
前言 在开发Web应用时,文件上传是一个常见需求。然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余。此时可以使用文件秒传技术通过识别重复文件,实现瞬间完成上传的效果,大大提升了用户体验…...
【Vue2】数据绑定_MVVM模型_数据代理_事件处理
目录 一、 数据绑定 1. Vue中有2种数据绑定的方式: 2. 响应式原理 el 与 data 的两种写法 二、 MVVM模型 三、 数据代理 1.回顾Object defineproperty方法 2. 何为数据代理 3.Vue中的数据代理 四、 事件处理 1.事件的基本使用: 2. Vue中的事…...
Python数据类型-dict
Python数据类型-dict 字典是Python中一种非常强大且常用的数据类型,它使用键-值对(key-value)的形式存储数据。 1. 字典的基本特性 无序集合:字典中的元素没有顺序概念可变(mutable):可以动态添加、修改和删除元素键必须唯一且不可变&…...
win10之mysql server 8.0.41安装
一 mysql server 下载 官网下载地址页面 https://dev.mysql.com/downloads/mysql/二 免装版使用步骤 1 解压 下载完成后,解压文件夹,如下所示: 2 执行安装命令 D:\soft\mysql\mysql-8.0.41-winx64\mysql-8.0.41-winx64\bin>mysqld --install Service successfully in…...
解决Oracle PL/SQL中“表或视图不存在“错误的完整指南
解决Oracle PL/SQL中"表或视图不存在"错误的完整指南 前言问题概述根本原因分析一、 编译时与运行时验证差异二、权限问题三、 Schema命名问题 实际案例演示案例1:动态分表查询案例2:权限不足的场景 实用排查步骤排查流程图最佳实践建议解决方…...
从实用的角度聊聊Linux下文本编辑器VIM
本文从实用的角度聊聊Vim的常用命令。何为实用?我举个不实用的例子大家就明白了,用vim写代码。;) “vim是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用,和Emacs并列成…...
MySQL的进阶语法8(SQL优化——insert、主键、order by、group by、limit、count和update)
目录 一、插入数据 1.1 insert 1.2 大批量插入数据 二、主键优化 2.1 数据组织方式 2.2 页分裂 2.2.1 主键顺序插入效果 2.2.2 主键乱序插入效果 2.3 页合并 2.4 索引设计原则 三、order by优化 3.1 执行以下两条语句(无索引) 3.2 创建索引…...
STM32F103C8T6单片机硬核原理篇:讨论GPIO的基本原理篇章1——只讨论我们的GPIO简单输入和输出
目录 前言 输出时的GPIO控制部分 标准库是如何操作寄存器完成GPIO驱动的初始化的? 问题1:如何掌握GPIO的编程细节——跟寄存器如何打交道 问题2:哪些寄存器,去哪里找呢? 问题三,寄存器的含义ÿ…...
FreeRTOS源码下载分享
FreeRTOS源码下载分享 官网下载太慢了,分享下FreeRTOSv202411 FreeRTOSv202411.00.zip 链接: https://pan.baidu.com/s/1P4sVS5WroYEl0WTlPD7GXg 提取码: g6aq...
PyArrow 核心技术与应用:高效数据处理与跨生态集成实践
Apache Arrow 作为列式内存数据格式的行业标准,其 Python 接口 PyArrow 正在重塑数据科学生态。本文深入解析 PyArrow 的核心计算能力,涵盖统计函数、分组聚合、窗口操作及跨库集成,通过完整代码示例演示如何利用其高性能特性优化数据处理流程…...
机试题——PCB印刷电路板布线
题目描述 在 PCB 印刷电路板设计中,器件之间的连线需要避免线路的阻抗值增大,而且器件之间还可能存在其他干扰源。为了简化问题,我们将电路板简化为一个 ( M * N ) 的矩阵,每个位置(单元格)的值表示其源干…...
数据化管理(一)---什么是数据化管理
目录 一、什么是数据化管理1.1 “聪明”的销售人员1.2 数据化管理的概念1.3 数据化管理的意义1.4 数据化管理的四个层次1.4.1 业务指导管理1.4.2 营运指导管理1.4.3 经营策略管理1.4.4 战略规划管理 1.5 数据化管理流程图1.5.1 分析需求1.5.2 收集数据1.5.3 整理数据1.5.4 分析…...
Android 10.0 通过广播控制systemui状态栏动态显示和隐藏功能实现
1.前言 在10.0的系统rom定制化开发中,在某些特定的产品开发中,需要通过接口来控制系统状态栏的显示和隐藏, 所以就需要了解systemui状态栏的显示构造过程,然后通过相关接口来显示和隐藏状态栏,接下来就来 实现相关的功…...
Linux服务器安装MinerU
安装MinerU 为了确保项目的稳定性和可靠性,我们在开发过程中仅对特定的软硬件环境进行优化和测试。这样当用户在推荐的系统配置上部署和运行项目时,能够获得最佳的性能表现和最少的兼容性问题。 这里我们以基础的 [[Linux服务器部署PaddleX实战教程]] 使…...
深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本
前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金…...
Vite 内联 CSS 和 JS 的解决方案
使用 vite-plugin-singlefile(推荐) 这个插件专门用于将整个 Vite 应用打包成单个 HTML 文件,内联所有 JS 和 CSS。 安装 pnpm i vite-plugin-singlefile -D配置 vite.config.js import { defineConfig } from vite import { viteSingleF…...
致敬生物信息学先驱:玛格丽特·戴霍夫(Margaret Dayhoff,1925-1983)
李升伟 编译 社论 发布于:2025年3月11日 《自然-计算科学》第五卷 第187页(2025年) 在玛格丽特戴霍夫(Margaret Dayhoff,1925-1983)百年诞辰之际,我们聚焦这位先驱在生物信息学领域留下的不朽…...
Knife4j文档请求异常 空指针
打开swagger文档报空指针异常 java.lang.NullPointerException: nullat springfox.documentation.oas.mappers.SchemaMapper.model(SchemaMapper.java:97)at springfox.documentation.oas.mappers.SchemaMapper.mapModel(SchemaMapper.java:85)at springfox.documentation.oas…...
笔记2——网络参考模型
一、OSI参考模型: 应用层: 报文 给应用程序提供接口 表示层: 进行数据格式的转换 会话层: 在通讯双方之间建立、管理和终止会话 传输层: 数据段;建立、维护、取消一次端到端的数据传输过程;控制…...
Spring AOP + Redis缓存设计实战:基于注解的优雅三防方案(击穿/穿透/雪崩)
文章目录 摘要 正文一、缓存设计的痛点与破局二、核心代码拆解:四层防御设计1. 注解驱动(ZywCacheable)2. 缓存击穿防护:双重检查锁3. 缓存穿透防护:空值标记4. 缓存雪崩防护:TTL随机算法 三、生产环境最佳…...
洛谷题单3-P5720 【深基4.例4】一尺之棰-python-流程图重构
题目描述 《庄子》中说到,“一尺之棰,日取其半,万世不竭”。第一天有一根长度为 a a a 的木棍,从第二天开始,每天都要将这根木棍锯掉一半(每次除 2 2 2,向下取整)。第几天的时候木…...
jdk21新特性详解使用总结
jdk21新特性详解总结 1.StringBuilder和StringBuffer新增了一个repeat方法 /*** Java 21的StringBuilder和StringBuffer新增了一个repeat方法*/public static void repeatStr(){var sbnew StringBuilder().repeat("*",10);System.out.println(sb);}运行结果如下&…...
解码 collections.Counter - 频率统计的利器
文章目录 前言一、什么是 collections.Counter?二、 基本用法:从创建到访问2.1 创建 Counter 对象2.2 访问计数三、 核心功能:更新与排序3.1 更新计数3.2 获取常见元素四、高级用法:数学运算与转换4.1 数学运算4.2 类型转换五、 实际应用:Counter 的威力5.1 词频统计5.2 在…...
Mysql基础笔记
# 1.SQL数据类型 可以去这篇文章看看: 最全 SQL 字段类型(4种)、属性(6种)总结:https://blog.csdn.net/weixin_45654582/article/details/119157403 ### 一.整数类型 ### 二.小数类型(2种) 1、浮点型:…...