【Linux笔记】进程间通信——匿名管道||进程池
🔥个人主页🔥:孤寂大仙V
🌈收录专栏🌈:Linux
🌹往期回顾🌹:【Linux笔记】动态库与静态库的理解与加载
🔖流水不争,争的是滔滔不
- 一、Linux进程间通信简介和目的
- 二、常见IPC方式
- 管道
- System V
- 三、匿名管道
- 工作原理
- 特性
- 管道读写规则
- 四、基于匿名管道的进程池
一、Linux进程间通信简介和目的
简介
进程间通信(IPC,Inter-Process Communication)是操作系统中不同进程之间交换数据、协调工作的核心机制。由于每个进程拥有独立的内存空间,彼此隔离,因此需要特定的技术手段实现跨进程协作。
进程间通信(IPC)是指运行在同一台计算机或不同计算机上的多个进程之间进行数据交换和通信的技术。由于每个进程都有自己的地址空间,它们无法直接访问彼此的数据,因此需要通过特定的机制实现通信。IPC是操作系统和多进程编程中的一个重要概念,广泛应用于分布式系统、多任务操作系统以及各种应用程序之间。
进程间通信的本质:是先让不同的进程,先看到同一份资源,然后才有通信的条件。
目的
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变
二、常见IPC方式
管道
类型:
- 匿名管道:用于父子进程间通信(半双工)。
- 有名管道(FIFO):可用于不相关进程(全双工)。
特点:
- 内核缓冲区存储数据,读写同步。
- 数据读取后即删除,不支持随机访问。
System V
-
共享内存(Shared Memory)
-
核心机制:多个进程直接访问同一块物理内存。
-
特点:
速度最快,无需数据复制。
需配合同步机制(如信号量、互斥锁)。 -
消息队列(Message Queue)
-
机制:进程通过发送 / 接收消息(带类型)通信。
-
特点:
消息按类型排序,支持异步通信。
消息队列在内核中持久化,直到被显式删除。 -
信号量(Semaphore)
-
作用:控制对临界资源的访问,实现同步与互斥。
-
类型:
二元信号量:0/1 状态(互斥锁)。
计数信号量:控制并发访问数量。
三、匿名管道
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
工作原理
通过父子进程继承关系,再将文件描述符关闭,实现一端写,一端读,就是匿名管道。
匿名管道是单向通信(半双工)数据只能从管道的一端写入,另一端读取,无法双向传输。内核缓冲区存储数据通过内核临时存储,大小通常为 64KB(可通过 ulimit -a 查看)。生命周期短,管道随创建它的进程(父进程)结束而自动销毁,无需手动清理。亲缘关系限制仅适用于父子进程或兄弟进程(通过 fork/exec 系列函数创建的进程)。
父进程以读写方式打开文件。父进程fork创建子进程,(进程具有独立性)子进程要拷贝一份PCB结构,PCB中包含了files_struct结构,files_struct中有一个指向struct file(文件)的指针数组,而文件描述符就是这个数组的下标。在拷贝后,子进程也就有了指向struct file(文件)的对应数组元素下标(文件描述符)。而struct file(文件)是独属于文件的,和进程没有关系,也就不用拷贝,也就是说此时父子进程公共区域就是 struct file。(实现不同进程看到同一份资源)。write是系统调用接口,会将数据放在内核缓冲区,底层定期刷新缓冲区将内容写到磁盘。
- 创建管道
通过系统调用 pipe(int fd[2]) 创建匿名管道,返回两个文件描述符:
fd[0]:读端(read end)。
fd[1]:写端(write end)。
- 数据流动
父进程通过 write(fd[1], buf, len) 向管道写入数据。
子进程通过 read(fd[0], buf, len) 读取数据。
子进程继承父进程的文件描述符表
匿名管道的示例
#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>// 9:
void ChildWrite(int wfd)//子进程写
{char c = 0;int cnt = 0;char buffer[1024];while (true){snprintf(buffer, sizeof(buffer), "I am child, pid: %d, cnt: %d\n", getpid(), cnt++);write(wfd,buffer,strlen(buffer));}
}void FatherRead(int rfd)//父进程读
{char buffer[1024];while (true){// sleep(100);sleep(1);buffer[0] = 0;ssize_t n = read(rfd, buffer, sizeof(buffer)-1);if(n > 0){buffer[n] = 0;std::cout << "child say: " << buffer << std::endl;// sleep(2);}else if(n == 0){std::cout << "n : " << n << std::endl;std::cout << "child 退出,我也退出";break;}else{break;}break;}
}int main()
{// 1. 创建管道int fds[2] = {0}; // fds[0]:读端 fds[1]: 写端int n = pipe(fds);if (n < 0){std::cerr << "pipe error" << std::endl;return 1;}std::cout << "fds[0]: " << fds[0] << std::endl;std::cout << "fds[1]: " << fds[1] << std::endl;// 2. 创建子进程pid_t id = fork();if (id == 0){// child// code// 3. 关闭不需要的读写端,形成通信信道// f -> r, c -> wclose(fds[0]);ChildWrite(fds[1]);close(fds[1]);exit(0);}// 3. 关闭不需要的读写端,形成通信信道// f -> r, c -> wclose(fds[1]);FatherRead(fds[0]);close(fds[0]);int status = 0;int ret = waitpid(id, &status, 0); // 获取到子进程的退出信息吗!!!if(ret > 0){printf("exit code: %d, exit signal: %d\n", (status>>8)&0xFF, status&0x7F);}return 0;
}
以上代码通过子进程写父进程写,形成信道。
特性
- 匿名管道,只能用来进行具有血缘关系的进程进行进程间通信。
- 管道是面向字节流的
- 管道是单向通信的-需要半双工的一种特殊情况
- 管道文件自带同步机制
同步机制的四种情况:
- 写入慢,读取快。读端就要阻塞,等写端的操作。
读端等待写端进行操作,写一条读一条。
- 写入快,读取慢。读端满了,写端就要阻塞。
把读取端也就是父进程,设置为slee(5),一瞬间写端子进程写满了,等待读端进程进行读取
- 写关,读端继续读。read就会读到返回值为0,表示文件的结尾。
- 读端关闭,写端继续写。写端的写入无意义。操作系统会杀掉进程。
管道读写规则
当没有数据可读时
- O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
- O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
当管道满的时候
- O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
- O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程
退出
当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
四、基于匿名管道的进程池
池化技术(Pooling Technology) 是一种通过预先创建并复用资源实例来优化系统性能的技术。其核心思想是减少资源频繁创建与销毁的开销,提升资源利用率。以下是关于池化技术的详细说明:
- 预创建资源:在系统初始化时,预先创建一定数量的资源实例(如进程、线程、数据库连接等)。
- 复用机制:当任务需要资源时,直接从池中获取已创建的实例,而非新建;任务完成后,资源归还池内供后续任务使用。
- 动态管理:部分池化技术支持根据负载动态调整资源数量(如扩容或缩容)。
进程池(Process Pool)适用场景:CPU 密集型任务(如并行计算、批量数据处理)。
特点:每个进程独立拥有内存空间,避免全局变量冲突。适合多核 CPU,但内存占用较高。
以下是基于匿名管道实现的简单进程池
#ifndef _PROCESS_POOL_HPP_
#define _PROCESS_POOL_HPP_#include <iostream>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include "Task.hpp"using namespace std;const int Poolnum = 5;
class Channel
{
public:Channel(int fd, pid_t pid): _wfd(fd), _supid(pid)~Channel() {}private:};class ChannelManager
{
public:ChannelManager(): _next(){}~ChannelManager() {}private:
}class ProcessPool
{
public:ProcessPool(): _process_num(){}void work(int rfd){}bool Start(){for (int i = 0; i < _process_num; i++){int pipefd[2] = {0}; // 创建管道int n = pipe(pipefd);if (n < 0){return false;}pid_t supid = fork(); // 创建进程if (supid < 0){return false;}else if (supid == 0){// 子进程读close(pipefd[1]); // 关闭子进程写端work(pipefd[0]);close(pipefd[0]);exit(1);}else{// 父进程写close(pipefd[0]); // 关闭子进程读端_cm.Insert(pipefd[1], supid);}}return true;}~ProcessPool() {}private:
};
#endif
整体框架是,有一个channel类是对单个的信道进行描述的,一个channelmanager类是对多个信道进行描述,最后是processpool是对进程的读写以及整体进行描述的。
以下是procress这个类内部函数的理解
bool Start(){for (int i = 0; i < _process_num; i++){int pipefd[2] = {0}; // 创建管道int n = pipe(pipefd);if (n < 0){return false;}pid_t supid = fork(); // 创建进程if (supid < 0){return false;}else if (supid == 0){// 子进程读close(pipefd[1]); // 关闭子进程写端work(pipefd[0]);close(pipefd[0]);exit(1);}else{// 父进程写close(pipefd[0]); // 关闭子进程读端_cm.Insert(pipefd[1], supid);}}return true;}
这里创建进程和匿名管道,让子进程读父进程写。注意信道是多个的数量由你自己来设定,所以设置一个for循环进行创建多个子进程与信道。把父进程的写端和进程的pid传给具体的channel信道,具体的工作让具体的channel信道完成。
ProcessPool(int num): _process_num(num){}void work(int rfd){int code = 0;ssize_t n = read(rfd, &code, sizeof(code));if (n > 0){if (n != sizeof(code)){return;}cout << "子进程pid->" << getpid() << "收到任务码->" << code << endl;_tm.Execute(code);}else if (n == 0){cout << "子进程退出" << endl;}else{cout << "读取错误" << endl;}}
上面是构造和子进程的读端是如何工作的,在这里设置一个任务码code,让子进程根据任务码的不同去做不同的工作。
void Run(){int taskcode = _tm.Code(); // 选择一个任务auto &c = _cm.Select(); // 选择一个信道c.Send(taskcode); // 发送任务码}void Stop(){// 父进程读端关闭_cm.StopSubProcess();// 回收子进程_cm.WaitSubProcess();}
上面代码是选择任务码,子进程需要收到任务码然后去做不同的工作,发给信道然后对应的子进程接收任务吗完成工作。这里在任务函数中在详细聊。 执行任务完成后父进程读端和子进程写端都需要关闭。
下面是channel类
class Channel
{
public:Channel(int fd, pid_t pid): _wfd(fd), _supid(pid){_name = "Channel-" + to_string(_wfd) + "-" + to_string(_supid);}void Send(int code){int n = write(_wfd, &code, sizeof(code));(void)n;}void Close(){close(_wfd);}void Wait(){pid_t rid = waitpid(_supid, nullptr, 0);(void)rid;}string Name(){return _name;}~Channel() {}private:int _wfd;pid_t _supid;string _name;
};
构造接收写端和pid,send()函数对应processpool类中的发送任f务码,要在具体的channel信道中发送任务码给子进程,每个子进程才能接受到对应的任务码。这里的close和wait就是关闭写端和回收子进程,对应processpool中的void Stop()。
下面是ChannelManager类
class ChannelManager
{
public:ChannelManager(int next = 0): _next(next){}void Insert(int fd, int pid){_channel.emplace_back(fd, pid);}Channel &Select(){auto &c = _channel[_next];_next++;_next %= _channel.size();return c;}void StopSubProcess(){for (auto &channel : _channel){channel.Close();std::cout << "关闭: " << channel.Name() << std::endl;}}void WaitSubProcess(){for (auto &channel : _channel){channel.Wait();std::cout << "回收: " << channel.Name() << std::endl;}}~ChannelManager() {}private:vector<Channel> _channel;int _next;
};
对通信信道用vector数组进程管理。 Channel &Select(),是选择任务码的时候在整个通信信道的数组中采用沦陷的方式进行选择信道。 void Insert(int fd, int pid)就是传过来写端和进程pid与channel的构造相关联与processpool的父进程传写端和pid相关联。void StopSubProcess() void WaitSubProcess()就是关闭写端和等待子进程与close()和wait()相关联。
任务码具体实现的函数
#pragma once
#include<iostream>
#include<vector>
using namespace std;typedef void(*task_t)();//函数指针void PrintLog()
{cout<<"我是一个打印日志的任务"<<endl;
}
void DownLoad()
{cout<<"我是一个下载的任务"<<endl;
}
void UpLoad()
{cout<<"我是一个上传的任务"<<endl;
}class TaskManager
{
public:TaskManager(){srand(time(nullptr)); //时间戳种子}int Code()//产生随机值{return rand()%_tasks.size();}void Register(task_t t)//注册任务{_tasks.push_back(t);}void Execute(int code){if(code>=0 && code<_tasks.size()){_tasks[code]();}}
private:vector<task_t> _tasks;
};
用函数指针,根据时间戳产生随机值,然后把对应注册的任务放进存储任务的数组中,最后execute函数根据产生的任务码在储存任务的数组中选择任务。
子进程work就是调用execute()把收到的任务码给这个函数然后让这个函数进行选择对应的任务。
void Run(){int taskcode = _tm.Code(); // 选择一个任务auto &c = _cm.Select(); // 选择一个信道c.Send(taskcode); // 发送任务码}
在次重新聊一下processpool中的run函数,通过调用task.hpp的code函数,获得任务码,然后通过Select()函数选择以一个信道,然后发送任务码给子进程,子进程接受任务码然后子进程开始运行。
ProcessPool.hpp
#ifndef _PROCESS_POOL_HPP_
#define _PROCESS_POOL_HPP_#include <iostream>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include "Task.hpp"
using namespace std;const int Poolnum = 5;
class Channel
{
public:Channel(int fd, pid_t pid): _wfd(fd), _supid(pid){_name = "Channel-" + to_string(_wfd) + "-" + to_string(_supid);}void Send(int code){int n = write(_wfd, &code, sizeof(code));(void)n;}void Close(){close(_wfd);}void Wait(){pid_t rid = waitpid(_supid, nullptr, 0);(void)rid;}string Name(){return _name;}~Channel() {}private:int _wfd;pid_t _supid;string _name;
};class ChannelManager
{
public:ChannelManager(int next = 0): _next(next){}void Insert(int fd, int pid){_channel.emplace_back(fd, pid);}Channel &Select(){auto &c = _channel[_next];_next++;_next %= _channel.size();return c;}void StopSubProcess(){for (auto &channel : _channel){channel.Close();std::cout << "关闭: " << channel.Name() << std::endl;}}void WaitSubProcess(){for (auto &channel : _channel){channel.Wait();std::cout << "回收: " << channel.Name() << std::endl;}}~ChannelManager() {}private:vector<Channel> _channel;int _next;
};class ProcessPool
{
public:ProcessPool(int num): _process_num(num){_tm.Register(PrintLog);_tm.Register(DownLoad);_tm.Register(UpLoad);}void work(int rfd){int code = 0;ssize_t n = read(rfd, &code, sizeof(code));if (n > 0){if (n != sizeof(code)){return;}cout << "子进程pid->" << getpid() << "收到任务码->" << code << endl;_tm.Execute(code);}else if (n == 0){cout << "子进程退出" << endl;}else{cout << "读取错误" << endl;}}bool Start(){for (int i = 0; i < _process_num; i++){int pipefd[2] = {0}; // 创建管道int n = pipe(pipefd);if (n < 0){return false;}pid_t supid = fork(); // 创建进程if (supid < 0){return false;}else if (supid == 0){// 子进程读close(pipefd[1]); // 关闭子进程写端work(pipefd[0]);close(pipefd[0]);exit(1);}else{// 父进程写close(pipefd[0]); // 关闭子进程读端_cm.Insert(pipefd[1], supid);}}return true;}void Run(){int taskcode = _tm.Code(); // 选择一个任务auto &c = _cm.Select(); // 选择一个信道c.Send(taskcode); // 发送任务码}void Stop(){// 父进程读端关闭_cm.StopSubProcess();// 回收子进程_cm.WaitSubProcess();}~ProcessPool() {}private:int _process_num = 5;ChannelManager _cm;TaskManager _tm;
};
#endif
Task.hpp
#pragma once
#include<iostream>
#include<vector>
using namespace std;typedef void(*task_t)();//函数指针void PrintLog()
{cout<<"我是一个打印日志的任务"<<endl;
}
void DownLoad()
{cout<<"我是一个下载的任务"<<endl;
}
void UpLoad()
{cout<<"我是一个上传的任务"<<endl;
}class TaskManager
{
public:TaskManager(){srand(time(nullptr)); //时间戳种子}int Code()//产生随机值{return rand()%_tasks.size();}void Register(task_t t)//注册任务{_tasks.push_back(t);}void Execute(int code){if(code>=0 && code<_tasks.size()){_tasks[code]();}}
private:vector<task_t> _tasks;
};
main.cc
#include "ProcessPool.hpp"
int main()
{ProcessPool pp(Poolnum);pp.Start();int ch=5;while(ch--){pp.Run();sleep(2);}pp.Stop();
}
相关文章:
【Linux笔记】进程间通信——匿名管道||进程池
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:Linux 🌹往期回顾🌹:【Linux笔记】动态库与静态库的理解与加载 🔖流水不争,争的是滔滔不 一、Linux进程间通…...
Spring Boot 3.4.3 基于 Caffeine 实现本地缓存
在现代企业级应用中,缓存是提升系统性能和响应速度的关键技术。通过减少数据库查询或复杂计算的频率,缓存可以显著优化用户体验。Spring Boot 3.4.3 提供了强大的缓存抽象支持,而 Caffeine 作为一款高性能的本地缓存库,因其优异的…...
windows使用nvm管理node版本
1.下载地址:https://github.com/coreybutler/nvm-windows/releases 选择nvm-setup.exe 2.安装,下载完成后,以管理员身份运行 nvm-setup.exe,选择默认安装,一路next 3.使用,安装完成后会打开一个命令行窗口࿰…...
vscode集成deepseek实现辅助编程(银河麒麟系统)【详细自用版】
针对开发者用户,可在Visual Studio Code中接入DeepSeek,实现辅助编程。 可参考我往期文章在银河麒麟系统环境下部署DeepSeek:基于银河麒麟桌面&&服务器操作系统的 DeepSeek本地化部署方法【详细自用版】 一、前期准备 (…...
智谱大模型(ChatGLM3)PyCharm的调试指南
前言 最近在看一本《ChatGLM3大模型本地化部署、应用开发和微调》,本文就是讨论ChatGLM3在本地的初步布设。(模型文件来自魔塔社区) 1、建立Pycharm工程 采用的Python版本为3.11 2、安装对应的包 2.1、安装modelscope包 pip install model…...
MySQL GROUP BY分组获取非聚合列值方法
在使用MySQL进行数据库查询时,如果你需要对数据按照某个或某些列进行分组(GROUP BY),并且希望在结果中包含非聚合列的值,你可以通过以下几种方法来实现: 1. 使用聚合函数 虽然这不是直接获取非聚合列值的…...
多路径 TCP 调度的另一面
参考前面的文章 一个原教旨的多路径 TCP 和 MP-BBR 公平性推演,一直都破而不立,不能光说怎样不好,还得说说现状情况下,该如何是好。 如果 receiver 乱序重排的能力有限(拜 TCP 所赐),如果非要在多路径上传输 TCP&…...
在Qt中判断输入的js脚本是否只包含函数
目前在使用QtScriptEngine,在利用evaluate注册子函数时,要求用户输入的js文件中的内容仅仅是函数,函数体外不能出现一些变量的声明、函数的调用等其他代码。 反复咨询DeepSeek后,终于给出了一个目前测试可用的代码: b…...
【Easylive】MySQL中LEFT JOIN与INNER JOIN的使用场景对比
【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 在MySQL数据库查询中,JOIN操作是最常用的操作之一,而LEFT JOIN和INNER JOIN是两种最基础的JOIN类型。理解它们的区别和适用场景对于编写高效、准确的SQL查询至关重要…...
Boost库中的谓词函数
Boost库中的谓词函数 谓词函数基础概念 在编程中,谓词函数(Predicate Function)是指返回布尔值(true或false)的函数,用于检测输入是否满足特定条件。谓词函数在STL算法和Boost库中被广泛使用,…...
人工智能之数学基础:基于初等反射矩阵完成矩阵的QR分解
本文重点 QR分解是矩阵分解中的一种重要方法,它将一个矩阵分解为一个正交矩阵Q和一个上三角矩阵R的乘积,即A=QR。这种分解在求解线性方程组、最小二乘问题、特征值计算等领域有着广泛应用。 QR分解的定义 QR分解就是应用了初等反射矩阵,不断的通过初等反射矩阵,然后将A变…...
AI应用案例(1)——智能工牌和会话质检
今天开辟一个新的模块,自己平时也搜集一些典型的行业应用案例,不如就记录到C站,同时和大家也是个分享好了。 今天分享的企业和产品,是循环智能的智能工牌。 这个产品应用场景清晰,针对的行业痛点合理,解决…...
碰一碰发视频系统--基于H5场景开发
碰一碰发视频#碰一碰发视频#开发基于H5的"碰一碰发视频"交互系统(类似华为/苹果的NFC碰传但通过移动端网页实现),需要结合近场通信(NFC/H5 API)和媒体传输技术。以下是具体实现方案 #碰一碰营销系统# #碰一…...
kotlin扩展函数的实现原理
1. 编译时转换 在编译时,Kotlin 扩展函数会被转换为静态函数。这个静态函数的第一个参数是接收者类型(也就是被扩展的类),而调用扩展函数时,实际上是调用这个静态函数,并将接收者对象作为第一个参数传入。…...
激活函数学习笔记
Sigmoid:梯度消失、指数计算复杂运行慢、输出不是以0为中心,梯度平滑便于求导tanh:以0为中心,其他与sigmoid相似ReLu:transformer常用,解决了梯度消失问题、计算复杂度低,存在神经元死亡问题和梯…...
【含文档+PPT+源码】基于Python爬虫二手房价格预测与可视化系统的设计与实现
项目介绍 本课程演示的是一款基于Python爬虫二手房价格预测与可视化系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 带你从零开始部署运行本套系统 该项…...
基于 Swoole 的高性能 RPC 解决方案
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
# 实时人脸识别系统:基于 OpenCV 和 Python 的实现
实时人脸识别系统:基于 OpenCV 和 Python 的实现 在当今数字化时代,人脸识别技术已经广泛应用于各种场景,从手机解锁到安防监控,再到智能门禁系统。今天,我将通过一个完整的代码示例,详细讲解如何使用 Pyt…...
python的global在编译层面的进阶理解
目录 报错情况 编译执行过程 (1)源代码(.py 文件) (2)编译阶段:解析 & 生成字节码 (3)解释执行:Python 虚拟机(PVM) 字节码…...
OpenCV、YOLO与大模型的区别与关系
OpenCV、YOLO 和大模型的区别与关系 1. OpenCV(Open Source Computer Vision Library) 定位:开源的计算机视觉基础库。功能:提供传统的图像处理算法(如图像滤波、边缘检测、特征提取)和基础工具ÿ…...
Buzz1.2.0视频语音转成TXT、SRT、VTT工具
buzz0.9.0.exe下载 https://download.csdn.net/download/u011000529/90551347 特征 导入音频和视频文件并导出文本到 TXT、SRT 和 VTT从您计算机的麦克风转录和翻译成文本(资源密集型且可能不是实时的,Demo)支持Whisper、 Whisper.cpp、Fast…...
Vue 2 和 Vue 3 中的钩子函数
Vue 钩子函数也被叫做生命周期钩子函数,它是 Vue 实例在其生命周期的不同阶段自动调用的函数。可以利用这些钩子函数在特定阶段执行自定义代码。 Vue 2 生命周期钩子函数 在 Vue 2 里,生命周期钩子函数可以在组件选项对象中定义。下面是一个简单的 Vue…...
零基础如何学会Appium自动化测试?
前言 appium是一款移动自动化测试工具,经常被用于实现UI自动化测试,其可支持安卓和IOS两大平台,还支持多种编程,因而得到了广泛的应用。此处便是立足于安卓平台,借助appium工具,使用python语言实现简单的自…...
用Python实现TCP代理
依旧是Python黑帽子这本书 先附上代码,我在原书代码上加了注释,更好理解 import sys import socket import threading#生成可打印字符映射 HEX_FILTER.join([(len(repr(chr(i)))3) and chr(i) or . for i in range(256)])#接收bytes或string类型的输入…...
SQL复杂查询与性能优化:医药行业ERP系统实战指南
SQL复杂查询与性能优化:医药行业ERP系统实战指南 一、医药行业数据库特性分析 在医药ERP系统中,数据库通常包含以下核心表结构: -- 药品主数据 CREATE TABLE drug_master (drug_id INT PRIMARY KEY,drug_name VARCHAR(255),specification …...
问题大集10-git使用commit提交中文显示乱码
(1)问题 (2)解决步骤 1) 设置全局编码为 UTF-8 git config --global core.quotepath false git config --global i18n.commitEncoding utf-8 git config --global i18n.logOutputEncoding utf-8 2) 显示或设…...
vue前端项目技术架构(第二版)
vue技术架构介绍 如下图所示,展示了项目系统的软件层次架构。该系统采用基于SOA(面向服务架构)思想的分层架构,分为四个主要层次:视图层、编译层、代码层和数据层。 视图层 浏览器:核心职责是解析并展示…...
Java 开发中的 AI 黑科技:如何用 AI 工具自动生成 Spring Boot 项目脚手架?
在 Java 开发领域,搭建 Spring Boot 项目脚手架是一项耗时且繁琐的工作。传统方式下,开发者需要手动配置各种依赖、编写基础代码,过程中稍有疏忽就可能导致配置错误,影响开发进度。如今,随着 AI 技术的迅猛发展&#x…...
计算机网络知识点汇总与复习——(一)计算机网络体系结构
Preface 计算机网络是考研408基础综合中的一门课程,它的重要性不言而喻。然而,计算机网络的知识体系庞大且复杂,各类概念、协议和技术相互关联,让人在学习时容易迷失方向。在进行复习时,面对庞杂的的知识点,…...
Copilot完全指南:AI编程助手的革命性实践
一、智能编程新时代:从代码补全到AI结对编程 1.1 Copilot的进化历程 2021年GitHub Copilot的诞生标志着编程辅助工具进入新纪元。与传统IDE补全工具相比,Copilot展现出三大革命性特征: 语义理解:基于GPT模型理解代码上下文跨文…...
Redis 梳理汇总目录
Redis 哨兵集群(Sentinel)与 Cluster 集群对比-CSDN博客 如何快速将大规模数据保存到Redis集群-CSDN博客 Redis的一些高级指令-CSDN博客 Redis 篇-CSDN博客...
5、无线通信基站的FPGA实现架构
基站(Base Station,BS),也称为公用移动通信基站,是无线电台站的一种形式,具体则指在一定的无线电覆盖区中,通过移动通信交换中心,与移动电话终端之间的信息传递的无线电收发信电台。…...
MySQL - 索引原理与优化:深入解析B+Tree与高效查询策略
文章目录 引言一、BTree索引核心原理1.1 索引数据结构演化1.2 BTree的存储结构通过主键查询(主键索引)商品数据的过程通过非主键(辅助索引)查询商品数据的过程 MySQL InnoDB 的索引原理 二、执行计划深度解析三、索引失效的六大陷…...
2025年数智化电商产业带发展研究报告260+份汇总解读|附PDF下载
原文链接:https://tecdat.cn/?p41286 在数字技术与实体经济深度融合的当下,数智化产业带正成为经济发展的关键引擎。 从云南鲜花产业带的直播热销到深圳3C数码的智能转型,数智化正重塑产业格局。2023年数字经济规模突破53.9万亿元ÿ…...
html实现手势密码
<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>手势密码</title><style>body {font-fam…...
机器学习(八):K-Means聚类原理与实战
声明:未经允许禁止转载与抄袭。 前言 k k k均值( k k k-means)聚类算法是一种经典的无监督聚类算法,本文将深入解析其理论原理,并在真是数据集上进行算法实践,话不多说,请看下文。 算法原理 …...
从 Word 到 HTML:使用 Aspose.Words 轻松实现 Word 文档的高保真转换
从 Word 到 HTML:使用 Aspose.Words 轻松实现 Word 文档的高保真转换 前言一、环境准备二、核心代码实现1. 将 Word 转换为 HTML 文件流2. 优化超链接样式 三、测试效果四、总结 前言 在日常开发中,我们经常需要将 Word 文档转换为 HTML,用于…...
SQLMesh调度系统深度解析:内置调度与Airflow集成实践
本文系统解析SQLMesh的两种核心调度方案:内置调度器与Apache Airflow集成。通过对比两者的适用场景、架构设计和操作流程,为企业构建可靠的数据分析流水线提供技术参考。重点内容包括: 内置调度器的轻量级部署与性能优化策略Airflow集成的端到…...
【深度学习新浪潮】Grok过去两周的进展一览(2025.04.01)
1. Grok过去两周的进展一览 根据公开信息,Grok在过去两周的主要进展如下: Grok 3正式上线并开放 xAI于2025年3月30日宣布Grok 3正式向所有Premium+订阅用户开放,并同步将X平台的Premium+订阅费用上涨至月费近50美元、年费350美元。这是继Grok 2之后的重大升级,其推理能力和…...
Vue表单数据回显失败技术解析与修复指南!!!
Vue表单数据回显失败技术解析与修复指南 🚀 在Vue.js应用开发中,「父子组件通信」「动态弹窗」是经典功能组合。但当遇到关键场景表单数据无法回显时,你是否也在深夜加班改bug?本文通过完整案例分析,揭秘该问题背后深层…...
【Office办公】【Excel】VLOOKUP函数-高速查找指定匹配数据,可合并2个表格
VLOOKUP 是 Excel 中常用的查找函数,用于在表格或区域中按列查找特定值并返回对应行的其他列数据。以下是详细使用方法及注意事项: 函数语法 VLOOKUP(查找值, 表格范围, 列索引号, [匹配方式])查找值:要查找的值(如单元格引用或…...
Java基础-21-基本语法-封装
封装(Encapsulation) 1. 什么是封装? 封装(Encapsulation)是面向对象编程(OOP)中的一个重要特性。它指的是将对象的属性和行为封装在一个类中,并提供访问控制机制,防止…...
SpringCloud概述
Spring Cloud Alibaba 1 系统架构演进 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。 1.1 单体架构 早期的软件系统通常是基于单体应用架构设计的,也就是将整个系统作为一个单一的…...
Kafka中的消息是如何存储的?
大家好,我是锋哥。今天分享关于【Kafka中的消息是如何存储的?】面试题。希望对大家有帮助; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Kafka 中,消息是通过 日志(Log) 的方式进行存储的。…...
主流Web3公链的核心区别对比
以下是当前主流Web3公链的核心区别对比表,涵盖技术架构、性能、生态等关键维度: 特性以太坊 (Ethereum)SolanaBNB ChainPolygonAvalanche共识机制PoS(信标链分片)PoH(历史证明) PoSPoSA(权益证…...
美甲预约管理系统基于Spring Boot SSM
目录 摘要 1. 引言 1.1 研究背景与意义 1.2 国内外研究现状 2. 系统需求分析 2.1 功能需求 2.2 非功能需求 3. 系统设计与实现 3.1 系统架构设计 3.2 关键技术实现 3.3 系统模块实现 3.3.1店铺管理 3.3.2商品管理 3.3.3用户管理 3.3.4订…...
Doris Streamloader安装教程
官方连接:Doris Streamloader - Apache Doris 简单概述:Doris Streamloader 是一款用于将数据导入 Doris 数据库的专用客户端工具。 step1:安装go环境 [rootlocalhost ~]# rpm --import https://mirror.go-repo.io/centos/RPM-GPG-KEY-GO-…...
用Python做数据分析之数据统计
接下来说说数据统计部分,这里主要介绍数据采样,标准差,协方差和相关系数的使用方法。 1、数据采样 Excel的数据分析功能中提供了数据抽样的功能,如下图所示。Python 通过 sample 函数完成数据采样。 2、数据抽样 Sample是进行…...
H.264编码解析与C++实现详解
一、H.264编码核心概念 1.1 分层编码结构 H.264采用分层设计,包含视频编码层(VCL)和网络抽象层(NAL)。VCL处理核心编码任务,NAL负责封装网络传输数据。 1.2 NALU单元结构 // NAL单元头部结构示例 struc…...
OpenAI即将开源!DeepSeek“逼宫”下,AI争夺战将走向何方?
OpenAI 终于要 Open 了。 北京时间 4 月 1 日凌晨,OpenAI 正式宣布:将在未来几个月内开源一款具备推理能力的语言模型,并开放训练权重参数。这是自 2019 年 GPT-2 部分开源以来,OpenAI 首次向公众开放核心模型技术。 【图片来源于…...