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

【Linux】——手撕线程池、简易线程池


前言

  在现代计算机编程领域,随着多核处理器和分布式系统的广泛应用,并发编程变得越来越重要。而线程作为实现并发的基本手段之一,其重要性不言而喻。然而,在实际的应用开发中,如何高效地管理和调度线程,以充分利用系统资源并提高程序的性能,一直是一个具有挑战性的问题。

  线程池作为一种被广泛应用的解决方案,为解决这一难题提供了一种优雅而有效的方法。它通过预先创建一定数量的线程,并合理地分配和管理任务,避免了频繁创建和销毁线程所带来的开销,同时也能更好地控制和协调线程的执行,从而显著提高程序的并发性能。

  本文将深入探讨线程池的概念、原理、应用场景以及实现细节,帮助读者全面了解线程池的相关知识,并能够在实际项目中灵活运用线程池来优化程序性能。


1.池化技术

池化技术是一种资源管理策略,它通过预先创建和缓存一定数量的资源(如数据库连接、线程、对象等),并在需要时从池中获取资源,使用完毕后将资源放回池中,以便下次复用。

池化技术的目的是提高资源的利用率,减少资源的创建和销毁开销,从而提高系统的性能和效率。

常见的池化类型:线程池、对象池等

2.线程池

线程池是池化技术的一种具体应用,是一种管理和复用线程的机制。

在传统的编程模式中,每当有任务需要执行时,就会创建一个新的线程来处理该任务。当任务完成后,线程就会被销毁。

频繁地创建和销毁线程会带来较大的开销,包括系统资源的分配和回收、线程上下文的切换等。

线程池则预先创建了一定数量的线程,并将它们维护在一个池子中。

当有任务到来时,从线程池中获取一个空闲线程来执行任务;当任务完成后,线程不会被销毁,而是放回线程池中,等待下一次任务的分配。

2.1线程池的工作流程

线程池的工作流程可以归纳为以下四个步骤

任务提交
线程分配
执行任务
线程回收

1.任务提交

  • 当有新的任务需要执行时,应用程序将任务提交给线程池。线程池会根据当前线程池的状态和配置策略来决定如何处理该任务。

2.线程分配 

  • 如果线程池中有空闲线程,那么直接将任务分配给该线程执行
  • 如果没有空闲线程,且当前线程数量未达到线程池的最大限制,那么会创建一个新的线程来执行任务
  • 如果线程数量已经达到最大限制,且任务队列已满,那么根据线程池的拒绝策略来处理该任务,常见的拒绝策略包括直接丢弃任务、抛出异常等

3.任务执行

  • 线程从线程池中获取到任务后,开始执行任务。在执行过程中,线程池会对线程进行监控和管理,确保任务的正常执行

4.线程回收

  • 当任务执行完成后,线程不会被销毁,而是放回线程池中,等待下一次任务的分配

3.标准线程池的实现

了解了什么是线程池,现在就来实现一下线程池

首先需要一个线程类,该类包含线程的基本信息

  • 线程tid
  • 线程数据
  • 执行函数

以下是Thread类的具体实现

thread.hpp

 struct ThreadData{void* _args;std::string _name;ThreadData(std::string& name,void* args):_name(name),_args(args){}};typedef void* (*fun_t)(void*);//线程要执行的函数的参数和返回值都为void*class Thread{private:fun_t func;       // 线程要执行的函数ThreadData _data; // 线程的名字和线程的数据pthread_t tid;    // 线程的tidpublic:Thread(std::string& name,fun_t function,void * args):func(function),_data(name,args){}//启动一个线程void start(){pthread_create(&tid,nullptr,func,_data._args);}//等待指定线程void join(){pthread_join(tid,nullptr);}std::string& name(){return _data._name;}~Thread(){}};

线程池中会将任务放入任务队列当中,每个线程都会从任务队列中获取任务

多线程并发访问同一个任务队列,任务队列是共享资源,因此需要锁来保护任务队列

我们平常使用锁对资源进行保护,需要两个操作

  • 加锁——pthread_mutex_lock
  • 解锁——pthread_mutex_unlock

每次都需要两行语句,很麻烦

有没有什么简单、不吃操作的办法

很简单,实现一个LockGuard类,让其实现自动加锁、解锁

  • 创建这个类对象时,自动加锁
  • 析构这个类对象时,自动解锁

以下是LockGuard类的具体实现

LockGuard.hpp

class Mutex{private:pthread_mutex_t* _mtx;public:Mutex(pthread_mutex_t* mtx):_mtx(mtx){}void lock(){pthread_mutex_lock(_mtx);}void unlock(){pthread_mutex_unlock(_mtx);}~Mutex(){}};//构造时加锁,//出作用域时,析构时解锁//一键实现自动加锁和解锁class LockGuard{private:Mutex _mtx;public:LockGuard(pthread_mutex_t* mtx):_mtx(mtx){_mtx.lock();}~LockGuard(){_mtx.unlock();}};

准备好了线程类和LockGuard类,则就是线程池类的实现

实现线程池,紧扣以下要求即可

  1. 提交任务
  2. 线程获取任务

盯着这两点,再进行扩展。

以下是线程池类的实现

ThreadPool.hpp

 template<class T>class ThreadPool{private:std::vector<Thread*> _threads;//用于存储找到所有线程的表int _num;//线程的数量std::queue<T> _task_queue;//任务队列static ThreadPool<T>* _pool_ptr;//线程池管理句柄,一种线程池只能出现一次static pthread_mutex_t _mtx;pthread_mutex_t lock;pthread_cond_t cond;bool stop=false;public:pthread_mutex_t* getMutex(){return &lock;}bool isEmpty(){return _task_queue.empty();}void waitCond(){pthread_cond_wait(&cond,&lock);}T getTask(){T task = _task_queue.front();_task_queue.pop();return task;}private:ThreadPool(int num):_num(num){pthread_mutex_init(&lock,nullptr);pthread_cond_init(&cond,nullptr);for(int i=1;i<=_num;i++){std::string name="Thread"+std::to_string(i);_threads.push_back(new Thread(name,runtine,this));}}public:~ThreadPool(){stop = true;pthread_cond_broadcast(&cond);for(auto& x: _threads){x->join();delete x;}pthread_mutex_destroy(&lock);pthread_cond_destroy(&cond);}//单例化模式static ThreadPool<T>* getThreadPoolPtr(int num){if(_pool_ptr == nullptr){LockGuard tmp(&_mtx);if(!_pool_ptr){_pool_ptr = new ThreadPool<T>(num);}}return _pool_ptr;}void push_task(const T& task){LockGuard tmp(&lock);//提交任务_task_queue.push(task);pthread_cond_signal(&cond);//唤醒一个线程}void run(){for(auto& x: _threads){x->start();std::cout<< x->name()<<"启动成功"<<std::endl;}}static void* runtine(void* arg){ThreadData* data = (ThreadData* ) arg;ThreadPool<T>* ptr = (ThreadPool<T>*)data->_args;while(true){T task;{LockGuard tmp(ptr->getMutex());while (ptr->isEmpty()){   if(stop) return nullptr;ptr->waitCond();}if(stop) return nullptr;task = ptr->getTask();//执行任务}}}};template<typename T>ThreadPool<T>* ThreadPool<T>::_pool_ptr = nullptr;template<typename T>pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;

4.简易线程池

上面的标准线程池实现起来是很麻烦的,且细节会更多

当有人让你现场手撕的时候,你不一定能写出来,就算写出来,也会浪费很多时间

能展现你的实力,且不会占用太多时间,我们实现一个简易的线程池即可

简易线程池的实现

class ThreadPool{private:int _num; // 线程数量static ThreadPool<task>* _ptr;std::vector<int> threads;static pthread_mutex_t* mutex;pthread_mutex_t *_mtx;pthread_cond_t *_cond;std::queue<tsak> _tasks;private:ThreadPoll(int num) : _num(num){pthread_mutex_init(_mtx);pthread_cond_init(_cond);}ThreadPool(ThreadPool &another) = delete;ThreadPool &operator=(ThreadPool &another) = delete;public:ThreadPool<task>* getThreadPoolPtr(int num){if(_ptr == nullptr){pthread_mutex_lock(mutex);if(_ptr == nullptr){_ptr = new ThreadPoll<task>(num);}pthread_mutrx_unlock(mutex);}return _ptr;}void push(task value){pthread_mutex_lock(_mtx);_tasks.push(value);pthread_mutex_unlock(_mtx);pthread_cond_signal(_cond);}bool isEmpty(){return _tasks.size()==0?true:false;}void  getTask(task& t){t = queue.front();queue.pop();}void* runFunction(void* arg){ThreadPoll<task>* ptr = (ThreadPoll<task>* )arg;while(true){task T;pthread_mutex_lock(_mtx);while(ptr->isEmpty()){pthread_cond_wait(_cond,_mtx);}ptr->getTask(T);pthread_mutex_unlock(_mtx);//}}void start(){for(int i=0;i<_num;i++){pthread_t tid = 0;pthread_create(&tid,nullptr,runFunction,(void*)this);threads.push_back(tid);}}};
template< class task>
ThreadPool<task>* ThreadPool<task>::_ptr = nullptr;
template< class task>
pthread_mutex_t* ThreadPool<task>::mutex = PTHREAD_MUTEX_INITIALIZER;

结语

  在本文中,我们一同探索了线程池的奇妙世界,了解了它的工作原理、优点以及具体的实现方法。线程池就像是一个神奇的“工厂”,高效地管理和调度着线程资源,让它们有条不紊地完成各项任务。

  在结束这份探索之旅时,你可能会思考一些更深层次的问题。比如,如何根据不同的业务需求选择最适合的线程池参数?在高并发环境下,如何进一步优化线程池的性能?这些问题都需要我们在实践中不断探索和总结。希望大家在今后的学习和工作中,能够继续深入研究线程池,将其运用到更多的场景中,为解决实际问题提供更多的思路和方法。

相关文章:

【Linux】——手撕线程池、简易线程池

前言 在现代计算机编程领域&#xff0c;随着多核处理器和分布式系统的广泛应用&#xff0c;并发编程变得越来越重要。而线程作为实现并发的基本手段之一&#xff0c;其重要性不言而喻。然而&#xff0c;在实际的应用开发中&#xff0c;如何高效地管理和调度线程&#xff0c;以充…...

使用mcp自定义编写mcp tool,使用 conda 启动,在cline中配置使用

自定义 mcp tool 例子 ## /langchain_learn/mcp学习/base_mcp_tool_study2.py # 导入必要模块 import os from typing import Optional from mcp.server.fastmcp import FastMCP# 初始化 MCP 服务器实例&#xff0c;指定服务器名称和版本 mcp_server FastMCP(name"DemoS…...

OpenEuler/CentOS一键部署OpenGauss数据库教程(脚本+视频)

&#x1f4cc;OpenEuler/CentOS一键安装OpenGauss数据库教程 为什么需要OpenGauss一键安装脚本&#xff1f; 手动部署OpenGauss数据库时&#xff0c;环境适配、依赖冲突等问题常让开发者头疼。尤其对新人而言&#xff0c;官方文档的配置步骤可能耗时数小时甚至引发未知报错。 …...

python如何快速删除文件夹中的大量文件

在 Python 中&#xff0c;删除文件夹中的大量小图片文件可以通过使用 os 模块或 shutil 模块来实现。以下是一个示例代码&#xff0c;展示了如何快速删除指定文件夹中的所有文件。如果你只需要删除小图片文件&#xff0c;可以添加额外的逻辑来检查文件大小。 以下是一个示例代…...

【mongodb】MongoDB的应用场景

目录 1.说明2.内容管理系统&#xff08;CMS&#xff09;2.1 场景描述2.2 MongoDB优势2.3 示例 3.实时分析与大数据3.1 场景描述3.2 MongoDB优势3.3 示例 4.移动应用后端4.1 场景描述4.2 MongoDB优势4.3 示例 5.游戏开发5.1 场景描述5.2 MongoDB优势5.3 示例 6.电子商务平台6.1 …...

使用 Swift 实现 LRU 缓存淘汰策略

&#x1f4cc; 实现思路 一、核心目标 我们要实现一个缓存类&#xff1a; 支持通过 get(key) 获取缓存的值&#xff1b;支持通过 put(key, value) 写入缓存&#xff1b;缓存容量有限&#xff0c;当超过容量时要淘汰最久未使用的元素。 二、为什么用「哈希表 双向链表」 功…...

【面试篇】Dubbo

基础概念 问题&#xff1a;请简要介绍一下 Dubbo 是什么&#xff0c;它的主要用途是什么&#xff1f;答案&#xff1a;Dubbo 是阿里巴巴开源的高性能、轻量级的分布式服务框架&#xff0c;它致力于提供高性能和透明化的 RPC 远程服务调用方案&#xff0c;以及 SOA 服务治理方案…...

01-STM32(介绍、工具准备、新建工程)p1-4

文章目录 工具准备和介绍硬件设备stm32简介和arm简介stm32简介STM32命名规则STM32选型STM32F103C8T6最小系统板引脚定义STM32启动配置STM32最小系统电路ARM简介 软件安装注册器件支持包安装ST-LINK驱动安装USB转串口驱动 新建工程创建stm32工程STM32工程编译和下载型号分类及缩…...

关于termux运行pc交叉编译的aarch64 elf的问题

在Linux系统上交叉编译Nim程序到Android Termux环境需要特殊处理&#xff0c;以下是详细的解决方案&#xff1a; 问题根源分析 ​​ABI不兼容​​ Android使用bionic libc而非标准glibc&#xff0c;直接编译的Linux ARM二进制无法直接运行 ​​动态链接错误​​ 默认编译会链…...

Ansible Playbook 进阶探秘:Handlers、变量、循环及条件判断全解析

192.168.60.100ansible.com192.168.60.110 client-1.com 192.168.60.120client-2.com192.168.60.130client-1.com 一、Handlers 介绍&#xff1a;在发生改变时执行的操作(类似puppet通知机制) 示例&#xff1a; 当apache的配置文件发生改变时&#xff0c;apache服务才会重启…...

解决GraalVM Native Maven Plugin错误:JAVA_HOME未指向GraalVM Distribution

目录 问题描述解决方案为什么需要这样配置&#xff1f; 问题描述 在你的项目中&#xff0c;如果你遇到了以下错误信息&#xff1a; [ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:0.10.5:test (native-test) on project DIctSystemInJavaUsing…...

006贪心——算法备赛

跨步问题 跳跃游戏|| 问题描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i]i j &…...

Hyperlane:高性能 Rust HTTP 服务器框架评测

Hyperlane&#xff1a;高性能 Rust HTTP 服务器框架评测 在当今快速发展的互联网时代&#xff0c;选择一个高效、可靠的 HTTP 服务器框架对于开发者来说至关重要。最近&#xff0c;我在评估各种服务器框架性能时&#xff0c;发现了一个名为 Hyperlane 的 Rust HTTP 服务器库&a…...

解锁多元养生密码,开启活力生活

在车水马龙、节奏飞快的现代社会&#xff0c;亚健康像阴霾一样&#xff0c;笼罩着不少人的生活。不少上班族长期久坐&#xff0c;肩颈酸痛&#xff1b;有的人作息混乱&#xff0c;皮肤状态差。想要驱散这些健康阴霾&#xff0c;拥抱活力生活&#xff0c;不妨解锁下面这些多元养…...

如何安全地访问AWS

如何安全地访问AWS 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 如何安全地访问AWS当可以使用AWS Organizations & IAM Identity Center时理想的访问方式补充:什么是IAM IIC…...

机器视觉工程师的专业精度决定职业高度,而专注密度决定成长速度。低质量的合群,不如高质量独处

在机器视觉行业&#xff0c;真正的技术突破往往诞生于深度思考与有效碰撞的辩证统一。建议采用「70%高质量独处30%精准社交」的钻石结构&#xff0c;构建可验证的技术能力护城河。记住&#xff1a;你的专业精度决定职业高度&#xff0c;而专注密度决定成长速度。 作为机器视觉工…...

Linux的 `sysctl` 命令 笔记250404

Linux的 sysctl 命令 笔记250404 sysctl 是 Linux 系统中用于 动态查看和修改内核运行时参数 的核心工具。它通过 /proc/sys/ 目录的虚拟文件系统接口&#xff0c;允许用户在不重启系统的前提下调整内核行为&#xff0c;涵盖网络、内存、文件系统等关键功能。 &#x1f4dc; 核…...

prism WPF 导航

导航和浏览器的后退前进是一样的功能 项目结构 App.xaml.cs using Prism.Ioc; using Prism.Modularity; using Prism.Unity; using PrismWpfApp.ViewModels; using PrismWpfApp.Views; using System; using System.Collections.Generic; using System.Configuration; using S…...

Pytorch实现线性分类

目录 1.导包 2.加载数据 3.获取X与Y数据 4.将X&#xff0c;Y数据转化成tensor张量, tensor张量必须是二维数据 5.用封装的API实现线性分类 5.1导包 5.2建模-神经网络&#xff08;二分类问题&#xff09; 5.3定义损失函数 5.4定义优化器 5.5定义训练过程 5.6 计算正确…...

使用人工智能大模型kimi,如何免费高效制作PPT?

今天我们学习人工智能大模型kimi&#xff0c;如何免费协助我们做班会PPT。 免费手把手讲解视频&#xff0c;请访问 https://edu.csdn.net/learn/40402/666417 第一步使用谷歌浏览器&#xff0c;搜索Kimi&#xff0c;看到Kimi智能助手&#xff0c;点击&#xff0c;在Kimi对话框…...

YOLO学习笔记 | 基于YOLO与光流融合的车牌识别方法研究(附Matlab代码)

🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓 基于YOLO与光流融合的车牌识别方法研究 🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓🍓 摘要 针对动态场景下车牌识别易受运动模糊影响的问题,提出结合YOLO目标检测与Lucas-Kanade…...

leetcode 数组总结篇

基础理论 数组&#xff1a;下标时从 0 开始的&#xff0c;地址是连续的&#xff0c;不能删除&#xff0c;只能覆盖&#xff1b;数组的实现&#xff1a;vector动态数组 常用操作 头文件 #include <iostream> #include <vector> #include <cstdint> // IN…...

CCF GESP C++编程 四级认证真题 2025年3月

C 四级 2025 年 03 月 题号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 答案 A B B D D C D D B B B B A A C 1 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 关于下述代码&#xff0c;说法错误的是&#xff08; &#xff09;。 int multiply(int x, int …...

元宇宙浪潮下,前端开发如何“乘风破浪”?

一、元宇宙对前端开发的新要求 元宇宙的兴起&#xff0c;为前端开发领域带来了全新的挑战与机遇。元宇宙作为一个高度集成、多维互动的虚拟世界&#xff0c;要求前端开发不仅具备传统网页开发的能力&#xff0c;还需要掌握虚拟现实&#xff08;VR&#xff09;、增强现实&#…...

室内指路机器人是否支持环境监测功能?

并非所有室内指路机器人都具备环境监测功能。那些支持环境监测的室内指路机器人&#xff0c;往往在设计上进行了针对性的优化&#xff0c;搭载了一系列先进且实用的传感器。温湿度传感器犹如一位敏锐的 “温度湿度侦探”&#xff0c;时刻精准地监测室内温度与湿度&#xff0c;为…...

redis的数据类型(1)

https://redis.io/docs/latest/develop/data-types/strings/ 社区版支持&#xff1a; String&#xff0c;字符串 Hash&#xff0c;key-value格式 List&#xff0c;根据插入顺序排序 Set&#xff0c;集合 Sorted set&#xff0c;有排序 Stream&#xff0c; Bitmap&#xff0c; …...

模运算核心性质与算法应用:从数学原理到编程实践

目录 &#x1f680;前言&#x1f31f;数学性质&#xff1a;模运算的理论基石&#x1f4af;基本定义&#xff1a;余数的本质&#x1f4af;四则运算规则&#xff1a;保持同余性的关键 &#x1f99c;编程实践&#xff1a;模运算的工程化技巧&#x1f4af;避免数值溢出&#xff1a;…...

使用 Messenger 跨进程通讯

在Android中使用Messenger进行跨进程通信&#xff08;IPC&#xff09;的步骤如下&#xff1a; 1. 服务端&#xff08;Service&#xff09;实现 1.1 创建Service并绑定Messenger public class MessengerService extends Service {private static final String TAG "Mess…...

css炫酷的3D水波纹文字效果实现详解

炫酷的3D水波纹文字效果实现详解 这里写目录标题 炫酷的3D水波纹文字效果实现详解项目概述技术栈核心实现1. 基础布局2. 渐变背景3. 文字效果实现3.1 基础样式3.2 文字漂浮动画 4. 水波纹效果4.1 模糊效果4.2 水波动画 5. 交互效果 技术要点项目难点与解决方案总结 项目概述 在…...

C++类的特殊成员函数:构造、拷贝构造与析构函数详解

目录 ​编辑一、构造函数 二、拷贝构造函数 三、析构函数 在C 编程中&#xff0c;类的特殊成员函数扮演着至关重要的角色&#xff0c;它们负责对象的创建、复制以及销毁过程。本文将深入探讨构造函数、拷贝构造函数和析构函数的概念、特性及应用场景&#xff0c;并结合代…...

ffmpeg常见命令3

文章目录 1. **文字水印&#xff08;Text Watermark&#xff09;**示例命令&#xff1a;更多选项&#xff1a; 2. **图片水印&#xff08;Image Watermark&#xff09;**示例命令&#xff1a;更多选项&#xff1a; 3. **画中画&#xff08;Picture-in-Picture, PIP&#xff09;…...

C# 中创建统一 API 接口实现方案

在 C# 中创建统一 API 接口需要从架构设计、技术选型和代码实现等多个层面进行规划。以下是详细的实现方案和完整示例代码&#xff1a; 一、技术选型与架构设计 框架选择 ASP.NET Core (6.0)RESTful API 规范 核心组件 统一响应格式&#xff1a;标准化 JSON 响应结构全局异常处…...

考研单词笔记 2025.04.04

accord n一致&#xff0c;符合&#xff0c;协议&#xff0c;条约v与…一致符合&#xff0c;给予&#xff0c;赠予 align v使一致&#xff0c;使对齐 alike a相同的&#xff0c;相似的ad相同地&#xff0c;相似地&#xff0c;同等地 analogous a类似的&#xff0c;相似的 co…...

leetcode 代码随想录 数组-区间和

题目 给定一个整数数组 Array&#xff0c;请计算该数组在每个指定区间内元素的总和。 输入&#xff1a; 第一行输入&#xff1a;为整数数组 Array 的长度 n&#xff0c;接下来 n 行&#xff0c;每行一个整数&#xff0c;表示数组的元素。随后的输入为需要计算总和的区间&…...

Linux学习笔记7:关于i.MX6ULL主频与时钟配置原理详解

以下是关于正点原子B站课程中 i.MX6ULL主频和时钟配置实验的博客内容框架与详细解析&#xff0c;结合实验原理、配置流程及关键代码实现&#xff0c;适合嵌入式开发者参考学习&#xff1a; 一、 实验背景 i.MX6ULL默认启动时由内部BootROM将主频设置为396MHz&#xff0c;但其…...

第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

✨前言&#xff1a;传参和状态管理&#xff0c;看似简单其实门道不少 在 Web 开发中&#xff0c;前端和后端最核心的交流方式就是“传参”&#xff0c;而“传参”除了涉及如何写代码获取参数&#xff0c;还藏着很多开发者容易忽略的细节&#xff1a; 为什么 URL 带了中文&…...

洛谷题单3-P1075 [NOIP 2012 普及组] 质因数分解-python-流程图重构

题目描述 已知正整数 n n n 是两个不同的质数的乘积&#xff0c;试求出两者中较大的那个质数。 输入格式 输入一个正整数 n n n。 输出格式 输出一个正整数 p p p&#xff0c;即较大的那个质数。 输入输出样例 输入 21输出 7说明/提示 1 ≤ n ≤ 2 1 0 9 1 \le n\…...

Vue组件化开发深度解析:Element UI与Ant Design Vue对比实践

一、Vue组件化开发的核心优势 1.1 组件化架构的天然优势 Vue的组件系统是其最核心的特性之一&#xff0c;采用单文件组件&#xff08;.vue&#xff09;形式&#xff0c;将HTML、CSS和JavaScript组合在同一个文件中&#xff0c;形成高内聚、低耦合的代码单元。这种设计显著提升…...

ctfshow VIP题目限免 robots后台泄露

根据题目提示是 robots后台泄露&#xff0c;所以我们试着访问它的后台文件 robots.txt 访问之后发现了有一个/flagishere.txt 目录文件。接着拼接访问它发现了 flag...

突破传统认知:聚类算法的底层逻辑与高阶应用全景解析

一、维度革命&#xff1a;重新定义聚类分析的认知边界 在人工智能的浩瀚星空中&#xff0c;聚类算法犹如一组精密的星际导航仪&#xff0c;帮助我们在无序的数据宇宙中发现隐藏的秩序。这项起源于人类本能分类需求的技术&#xff0c;经历了从简单分组到智能识别的蜕变&#xf…...

获取ssh密钥

git bash GitHub官网: Redirecting… ssh-keygen -t rsa -C “git账号” 出现id_rsa.pub 登录github添加 将id_rsa.pub中内容复制 点击SSH and GPG keys 点击New SSH key 起个名字 将id_rsa.pub中内容复制到这里 报错&#xff1a; ssh: connect to host github.com port 2…...

MINIQMT学习课程Day7

在上一篇&#xff0c;我们安装好xtquant&#xff0c;qmt以及python后&#xff0c;这一章&#xff0c;我们学习如何使用xtquant 本章学习&#xff0c;如何获取账号的资金使用状况。 首先&#xff0c;打开qmt&#xff0c;输入账号密码&#xff0c;选择独立交易。 进入交易界面&…...

`accept_ra` 和 `autoconf` 和 `forwarding` 的关系 笔记250404

accept_ra 和 autoconf 和 forwarding 的关系 笔记250404 在 Linux 的 IPv6 网络配置中&#xff0c;accept_ra、autoconf 和 forwarding 是三个密切相关的核心参数&#xff0c;它们的组合直接影响设备在网络中的角色&#xff08;主机或路由器&#xff09;和地址配置行为。以下是…...

leetcode数组-二分查找

题目 题目链接&#xff1a;https://leetcode.cn/problems/binary-search/ 文章讲解&#xff1a;https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1fA4y1o715 给定一个 n 个元素有序的&…...

vector的介绍与代码演示

由于以后我们写OJ题时会经常使用到vector&#xff0c;所以我们必不可缺的是熟悉它的各个接口。来为我们未来作铺垫。 首先&#xff0c;我们了解一下&#xff1a; https://cplusplus.com/reference/vector/ vector的概念&#xff1a; 1. vector是表示可变大小数组的序列容器…...

SDK中窗口调用

存在窗口A和B的win32程序 , 当点击窗口A中的按钮后会弹出窗口B #include <windows.h>// 窗口 B 的窗口过程 LRESULT CALLBACK WindowProcB(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {switch (uMsg) {case WM_DESTROY:PostQuitMessage(0);break;default:ret…...

Web Service技术

Web Service 是一种基于网络的、分布式的技术&#xff0c;用于在不同的应用程序之间进行通信和数据交换。以下是关于它的详细介绍&#xff1a; 定义与概念 Web Service 是一种通过互联网协议&#xff08;如 HTTP&#xff09;提供服务的软件组件&#xff0c;它使用标准的 XML …...

使用内存数据库来为mapper层的接口编写单元测试

简介 使用内存数据库来测试mapper层的sql代码&#xff0c;这种方式可以让测试案例摆脱对数据库的依赖&#xff0c;进而变得可重复执行。 这里选择的内存数据库是h2&#xff0c;它是纯java编写的关系型数据库&#xff0c;开源免费&#xff0c;而且轻量级的&#xff0c;性能较好…...

PowerMonitor的使用步骤

PowerMonitor是功耗分析中常用的测试和分析工具&#xff0c;不仅精度高&#xff0c;而且遇到需要找方案提功耗单的时候&#xff0c;有时还需要PowerMonitor的数据作为辅助日志。 1.先接上假电池正负极&#xff0c;再按PowerMonior的电源键 2.桌面点击PowerMonitor快捷图标 3.调…...

【C++经典例题】杨辉三角问题

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;C经典例题 期待您的关注 目录 一、问题描述 二、解题思路 解法 1 思路 解法 2 思路 三、代码实现 解法 1 代码 解法 2 代码…...