C++事件驱动编程从入门到实战:深入理解与高效应用
C++事件驱动编程从入门到实战:深入理解与高效应用
在现代软件开发中,事件驱动编程(Event-Driven Programming)作为一种流行的编程范式,被广泛应用于图形用户界面(GUI)、网络通信、游戏开发等众多领域。它通过定义和响应各种事件,实现程序的灵活性和可扩展性。C++,作为一门性能卓越的编程语言,结合事件驱动编程,可构建高效、响应迅速的应用程序。本文将从事件驱动编程的基本概念入手,深入探讨在C++中的实现方式,并通过详细的实战案例,帮助开发者全面掌握C++事件驱动编程的技巧与应用。
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用,熟悉DICOM医学影像及DICOM协议,业余时间自学JavaScript,Vue,qt,python等,具备多种混合语言开发能力。撰写博客分享知识,致力于帮助编程爱好者共同进步。欢迎关注、交流及合作,提供技术支持与解决方案。
技术合作请加本人wx(注明来自csdn):xt20160813
目录
- 事件驱动编程基础概念
- 什么是事件驱动编程
- 事件驱动编程的特点
- 与其他编程范式的比较
- C++中事件驱动编程的应用场景
- C++中实现事件驱动编程的基本方法
- 使用回调函数
std::function
与Lambda表达式- 观察者模式
- 事件循环的实现
- 实战案例:构建简单的事件驱动系统
- 案例一:基于回调函数的事件管理器
- 案例二:使用观察者模式实现事件驱动
- 案例三:实现一个简单的事件循环
- 案例四:结合Boost.Asio进行异步事件处理
- 优化与高级技巧
- 多线程与事件驱动的结合
- 高效的事件循环设计
- 使用事件队列提升性能
- 避免常见的事件处理陷阱
- 现代C++中的事件驱动编程工具与库
- Boost.Asio
- Qt框架的事件系统
- libuv与Node.js的事件驱动模型
- 总结
- 参考资料
事件驱动编程基础概念
什么是事件驱动编程
事件驱动编程是一种编程范式,其中程序的执行流程由外部事件的发生来触发。事件可以是用户的操作(如鼠标点击、键盘输入)、系统消息(如定时器到期、网络数据到达)或其他程序产生的信号。事件驱动程序通常包含一个事件循环(Event Loop),不断监听并处理各种事件,确保程序对各种输入做出及时响应。
事件驱动编程的特点
- 响应式:程序根据事件的发生做出反应,而不是按固定的执行顺序运行。
- 解耦性:事件的产生与处理相互独立,提高了代码的模块化与可维护性。
- 灵活性:易于扩展和修改,因为新的事件处理逻辑可以独立添加。
- 高效性:在适当设计下,可以有效利用系统资源,处理高并发或实时性要求高的任务。
与其他编程范式的比较
- 顺序执行:按照代码编写的顺序逐行执行,适用于简单、线性的任务。
- 事件驱动:以事件作为程序执行的触发点,适用于复杂、多变的交互场景。
- 多线程:通过同时运行多个线程来处理任务,适用于需要并行计算的场景。
- 并行编程:更高层次的并行处理,通常涉及多线程或分布式系统。
事件驱动编程与多线程、并行编程可以结合使用,以实现更高效的程序设计。
C++中事件驱动编程的应用场景
- 图形用户界面(GUI)应用:例如,按钮点击、窗口移动等用户操作触发相应事件。
- 网络通信:处理网络请求、数据接收与发送等异步事件。
- 游戏开发:响应用户输入、游戏状态变化、物理碰撞等事件。
- 实时系统:如金融交易系统,需要及时响应外部变化。
- 嵌入式系统:处理传感器输入、硬件中断等事件。
C++中实现事件驱动编程的基本方法
在C++中,实现事件驱动编程的方法多种多样,以下几种方式是最为常见和基础的:
使用回调函数
回调函数是一种通过函数指针或函数对象,将函数的执行权交给调用者的机制。在事件驱动编程中,回调函数用于响应特定事件的发生。
示例代码
#include <iostream>
#include <functional>
using namespace std;// 定义事件类型
typedef function<void(int)> EventCallback;// 事件管理器类
class EventManager {
public:// 注册回调函数void registerEvent(EventCallback cb) {callbacks.push_back(cb);}// 触发事件void triggerEvent(int eventId) {cout << "Event " << eventId << " triggered.\n";for(auto& cb : callbacks) {cb(eventId);}}private:vector<EventCallback> callbacks;
};// 回调函数实现
void onEventReceived(int eventId) {cout << "Callback received event: " << eventId << endl;
}int main() {EventManager manager;// 注册回调函数manager.registerEvent(onEventReceived);// 使用Lambda表达式注册回调manager.registerEvent([](int id) {cout << "Lambda callback for event: " << id << endl;});// 触发事件manager.triggerEvent(1);manager.triggerEvent(2);return 0;
}
输出结果
Event 1 triggered.
Callback received event: 1
Lambda callback for event: 1
Event 2 triggered.
Callback received event: 2
Lambda callback for event: 2
关键注释
typedef function<void(int)> EventCallback; // 定义回调函数的类型,接受一个整数参数class EventManager {
public:void registerEvent(EventCallback cb) { // 注册回调函数callbacks.push_back(cb);}void triggerEvent(int eventId) { // 触发事件,调用所有注册的回调函数cout << "Event " << eventId << " triggered.\n";for(auto& cb : callbacks) {cb(eventId);}}private:vector<EventCallback> callbacks; // 存储所有的回调函数
};void onEventReceived(int eventId) { // 具体的回调函数实现cout << "Callback received event: " << eventId << endl;
}
std::function
与Lambda表达式
C++11引入了**std::function
和Lambda表达式**,这两者结合使用,使得回调函数的注册和调用更加灵活和强大。std::function
可以存储各种可调用对象,包括函数指针、Lambda表达式、绑定后的成员函数等。
示例代码
#include <iostream>
#include <functional>
using namespace std;// 事件管理器类
class EventManager {
public:// 注册回调函数void registerEvent(const function<void(string)>& cb) {callbacks.push_back(cb);}// 触发事件void triggerEvent(const string& message) {cout << "Event triggered with message: " << message << endl;for(auto& cb : callbacks) {cb(message);}}private:vector<function<void(string)>> callbacks;
};int main() {EventManager manager;// 注册Lambda表达式回调,捕获外部变量string prefix = "Received: ";manager.registerEvent([prefix](string msg) {cout << prefix << msg << endl;});// 注册成员函数回调struct Receiver {void handleEvent(string msg) {cout << "Receiver handling event: " << msg << endl;}};Receiver receiver;manager.registerEvent(bind(&Receiver::handleEvent, &receiver, placeholders::_1));// 触发事件manager.triggerEvent("Hello, World!");return 0;
}
输出结果
Event triggered with message: Hello, World!
Received: Hello, World!
Receiver handling event: Hello, World!
关键注释
class EventManager {
public:void registerEvent(const function<void(string)>& cb) { // 使用std::function注册回调callbacks.push_back(cb);}void triggerEvent(const string& message) { // 触发事件,调用所有回调cout << "Event triggered with message: " << message << endl;for(auto& cb : callbacks) {cb(message);}}private:vector<function<void(string)>> callbacks; // 存储各种可调用对象
};manager.registerEvent([prefix](string msg) { // 使用Lambda表达式注册回调,捕获外部变量prefixcout << prefix << msg << endl;
});Receiver receiver;
manager.registerEvent(bind(&Receiver::handleEvent, &receiver, placeholders::_1)); // 绑定成员函数作为回调
观察者模式
观察者模式是一种设计模式,其中主题(Subject)维护一组观察者(Observer),并在自身状态发生变化时通知所有观察者。C++中,回调函数常用于实现观察者模式,增强程序的可扩展性和解耦性。
示例代码
#include <iostream>
#include <vector>
#include <functional>
using namespace std;// 观察者接口
typedef function<void(int)> Observer;// 主题类
class Subject {
public:// 添加观察者void addObserver(Observer obs) {observers.push_back(obs);}// 移除所有观察者void clearObservers() {observers.clear();}// 通知所有观察者void notify(int state) {for(auto& obs : observers) {obs(state);}}// 改变状态并通知观察者void setState(int newState) {state = newState;notify(state);}private:vector<Observer> observers;int state;
};// 具体观察者A
void observerA(int state) {cout << "Observer A received state: " << state << endl;
}// 具体观察者B
class ObserverB {
public:void onNotify(int state) {cout << "Observer B received state: " << state << endl;}
};int main() {Subject subject;// 注册观察者Asubject.addObserver(observerA);// 注册观察者B的成员函数ObserverB obsB;subject.addObserver([&obsB](int state) {obsB.onNotify(state);});// 改变状态,通知观察者subject.setState(10);return 0;
}
输出结果
Observer A received state: 10
Observer B received state: 10
关键注释
typedef function<void(int)> Observer; // 定义观察者类型,接受一个整数参数class Subject {
public:void addObserver(Observer obs) { // 添加观察者observers.push_back(obs);}void notify(int state) { // 通知所有观察者for(auto& obs : observers) {obs(state);}}void setState(int newState) { // 改变状态并通知state = newState;notify(state);}private:vector<Observer> observers; // 存储所有观察者int state; // 当前状态
};void observerA(int state) { // 具体观察者A的回调实现cout << "Observer A received state: " << state << endl;
}class ObserverB {
public:void onNotify(int state) { // 具体观察者B的回调实现cout << "Observer B received state: " << state << endl;}
};subject.addObserver([](int state) { // 注册观察者B的成员函数作为回调obsB.onNotify(state);
});
事件循环的实现
事件循环(Event Loop)是事件驱动编程的核心部分,它不断监听和分发事件,实现程序对各种事件的响应。C++中,可以通过循环结构结合事件队列,手动实现一个简单的事件循环。
示例代码
#include <iostream>
#include <queue>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;// 定义事件类型
typedef function<void()> Event;// 事件循环类
class EventLoop {
public:// 添加事件到队列void addEvent(Event event) {unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one();}// 启动事件循环void run() {while(running) {Event event;{unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break;event = eventQueue.front();eventQueue.pop();}if(event) event();}}// 停止事件循环void stop() {unique_lock<mutex> lock(mtx);running = false;cv.notify_all();}private:queue<Event> eventQueue;mutex mtx;condition_variable cv;bool running = true;
};int main() {EventLoop loop;// 启动事件循环在新线程thread loopThread([&loop]() {loop.run();});// 添加事件loop.addEvent([]() {cout << "Event 1 executed." << endl;});loop.addEvent([]() {cout << "Event 2 executed." << endl;});// 模拟延迟后添加事件this_thread::sleep_for(chrono::seconds(1));loop.addEvent([]() {cout << "Event 3 executed after delay." << endl;});// 停止事件循环this_thread::sleep_for(chrono::seconds(2));loop.stop();loopThread.join();return 0;
}
输出结果
Event 1 executed.
Event 2 executed.
Event 3 executed after delay.
关键注释
typedef function<void()> Event; // 定义事件类型,不带参数的可调用对象class EventLoop {
public:void addEvent(Event event) { // 添加事件到队列unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one(); // 通知事件循环有新事件}void run() { // 事件循环的主要运行函数while(running) {Event event;{unique_lock<mutex> lock(mtx);// 等待直到有事件或停止信号cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break; // 如果停止且队列为空,退出循环event = eventQueue.front(); // 获取下一个事件eventQueue.pop();}if(event) event(); // 执行事件}}void stop() { // 停止事件循环unique_lock<mutex> lock(mtx);running = false;cv.notify_all(); // 通知所有等待线程}private:queue<Event> eventQueue; // 事件队列mutex mtx; // 互斥锁保护队列condition_variable cv; // 条件变量用于事件通知bool running = true; // 是否继续运行事件循环
};
实战案例:构建简单的事件驱动系统
通过几个具体的实战案例,展示在C++中如何应用事件驱动编程,来解决实际问题。
案例一:基于回调函数的事件管理器
场景描述:
实现一个简单的事件管理器,支持注册多个回调函数,并在事件触发时调用所有回调。
实现代码
#include <iostream>
#include <functional>
#include <vector>
using namespace std;// 定义事件类型
typedef function<void(int)> EventCallback;// 事件管理器类
class EventManager {
public:// 注册回调函数void registerEvent(EventCallback cb) {callbacks.push_back(cb);}// 触发事件void triggerEvent(int eventId) {cout << "Triggering event ID: " << eventId << endl;for(auto& cb : callbacks) {cb(eventId);}}private:vector<EventCallback> callbacks; // 存储所有回调函数
};// 回调函数实现
void onEvent1(int id) {cout << "Callback onEvent1 received event ID: " << id << endl;
}void onEvent2(int id) {cout << "Callback onEvent2 received event ID: " << id << endl;
}int main() {EventManager manager;// 注册回调函数manager.registerEvent(onEvent1);manager.registerEvent(onEvent2);// 使用Lambda表达式注册回调manager.registerEvent([](int id) {cout << "Lambda callback received event ID: " << id << endl;});// 触发事件manager.triggerEvent(100);manager.triggerEvent(200);return 0;
}
输出结果
Triggering event ID: 100
Callback onEvent1 received event ID: 100
Callback onEvent2 received event ID: 100
Lambda callback received event ID: 100
Triggering event ID: 200
Callback onEvent1 received event ID: 200
Callback onEvent2 received event ID: 200
Lambda callback received event ID: 200
关键注释
typedef function<void(int)> EventCallback; // 定义回调函数类型,接受一个整数参数class EventManager {
public:void registerEvent(EventCallback cb) { // 注册回调函数callbacks.push_back(cb);}void triggerEvent(int eventId) { // 触发事件,并调用所有回调cout << "Triggering event ID: " << eventId << endl;for(auto& cb : callbacks) {cb(eventId);}}private:vector<EventCallback> callbacks; // 存储所有回调函数的容器
};void onEvent1(int id) { // 具体回调函数1cout << "Callback onEvent1 received event ID: " << id << endl;
}void onEvent2(int id) { // 具体回调函数2cout << "Callback onEvent2 received event ID: " << id << endl;
}
案例二:使用观察者模式实现事件驱动
场景描述:
通过观察者模式,实现主题与观察者的解耦,观察者在主题状态变更时自动接收通知。
实现代码
#include <iostream>
#include <vector>
#include <functional>
#include <string>
using namespace std;// Observer类型定义
typedef function<void(const string&)> Observer;// 主题类
class Subject {
public:// 注册观察者void addObserver(Observer obs) {observers.push_back(obs);}// 移除所有观察者void clearObservers() {observers.clear();}// 通知所有观察者void notifyObservers(const string& message) {for(auto& obs : observers) {obs(message);}}// 更改主题状态并通知观察者void setState(const string& newState) {state = newState;cout << "Subject state changed to: " << state << endl;notifyObservers(state);}private:vector<Observer> observers; // 存储观察者的容器string state; // 主题的状态
};// 具体观察者A
void observerA(const string& message) {cout << "Observer A received message: " << message << endl;
}// 具体观察者B,使用成员函数作为回调
class ObserverB {
public:void handleUpdate(const string& message) {cout << "Observer B received message: " << message << endl;}
};int main() {Subject subject;// 注册观察者Asubject.addObserver(observerA);// 注册观察者B的成员函数ObserverB obsB;subject.addObserver([&obsB](const string& msg) {obsB.handleUpdate(msg);});// 改变主题状态,触发通知subject.setState("State 1");subject.setState("State 2");return 0;
}
输出结果
Subject state changed to: State 1
Observer A received message: State 1
Observer B received message: State 1
Subject state changed to: State 2
Observer A received message: State 2
Observer B received message: State 2
关键注释
typedef function<void(const string&)> Observer; // 定义观察者的回调函数类型class Subject {
public:void addObserver(Observer obs) { // 添加观察者observers.push_back(obs);}void notifyObservers(const string& message) { // 通知所有观察者for(auto& obs : observers) {obs(message);}}void setState(const string& newState) { // 设置状态并通知观察者state = newState;cout << "Subject state changed to: " << state << endl;notifyObservers(state);}private:vector<Observer> observers; // 存储所有观察者的容器string state; // 主题的当前状态
};void observerA(const string& message) { // 具体观察者A的回调实现cout << "Observer A received message: " << message << endl;
}class ObserverB { // 具体观察者B
public:void handleUpdate(const string& message) { // 观察者B的成员函数cout << "Observer B received message: " << message << endl;}
};subject.addObserver([&obsB](const string& msg) { // 注册观察者B的成员函数作为回调obsB.handleUpdate(msg);
});
案例三:实现一个简单的事件循环
场景描述:
实现一个基本的事件循环,模拟事件的监听和处理过程,使程序能够持续运行并响应外部事件。
实现代码
#include <iostream>
#include <queue>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
using namespace std;// 定义事件类型
typedef function<void()> Event;// 事件循环类
class EventLoop {
public:EventLoop() : running(false) {}// 启动事件循环void start() {running = true;loopThread = thread(&EventLoop::run, this);}// 添加事件到队列void addEvent(Event event) {unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one();}// 停止事件循环void stop() {unique_lock<mutex> lock(mtx);running = false;cv.notify_all();lock.unlock();if(loopThread.joinable()) {loopThread.join();}}~EventLoop() {if(running) {stop();}}private:// 事件循环的主要执行函数void run() {while(running) {Event event;{unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break;event = eventQueue.front();eventQueue.pop();}if(event) {event(); // 执行事件}}}queue<Event> eventQueue; // 存储事件的队列mutex mtx; // 互斥锁condition_variable cv; // 条件变量bool running; // 是否运行事件循环thread loopThread; // 事件循环线程
};// 示例事件处理函数
void handleEvent1() {cout << "Handling Event 1" << endl;
}void handleEvent2() {cout << "Handling Event 2" << endl;
}int main() {EventLoop loop;loop.start();// 添加事件loop.addEvent(handleEvent1);loop.addEvent([]() {cout << "Handling Event 3 (Lambda)" << endl;});// 模拟延迟后添加事件this_thread::sleep_for(chrono::seconds(1));loop.addEvent(handleEvent2);// 模拟延迟后停止事件循环this_thread::sleep_for(chrono::seconds(2));loop.stop();return 0;
}
输出结果
Handling Event 1
Handling Event 3 (Lambda)
Handling Event 2
关键注释
typedef function<void()> Event; // 定义不带参数的事件类型class EventLoop {
public:EventLoop() : running(false) {}void start() { // 启动事件循环,创建事件循环线程running = true;loopThread = thread(&EventLoop::run, this);}void addEvent(Event event) { // 添加事件到队列并通知事件循环unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one();}void stop() { // 停止事件循环,等待线程结束unique_lock<mutex> lock(mtx);running = false;cv.notify_all();lock.unlock();if(loopThread.joinable()) {loopThread.join();}}~EventLoop() { // 析构函数,确保事件循环停止if(running) {stop();}}private:void run() { // 事件循环的主要执行函数while(running) {Event event;{unique_lock<mutex> lock(mtx);// 等待直到有事件或停止信号cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break; // 如果停止且队列为空,退出循环event = eventQueue.front(); // 获取下一个事件eventQueue.pop();}if(event) {event(); // 执行事件}}}queue<Event> eventQueue; // 事件队列mutex mtx; // 互斥锁保护队列condition_variable cv; // 条件变量用于事件通知bool running; // 事件循环是否在运行thread loopThread; // 事件循环线程
};void handleEvent1() { // 事件1的处理函数cout << "Handling Event 1" << endl;
}int main() {EventLoop loop;loop.start(); // 启动事件循环loop.addEvent(handleEvent1); // 添加事件1loop.addEvent([]() { // 添加事件3,使用Lambda表达式cout << "Handling Event 3 (Lambda)" << endl;});this_thread::sleep_for(chrono::seconds(1)); // 延迟1秒loop.addEvent(handleEvent2); // 添加事件2this_thread::sleep_for(chrono::seconds(2)); // 延迟2秒loop.stop(); // 停止事件循环return 0;
}
案例四:结合Boost.Asio进行异步事件处理
场景描述:
使用Boost.Asio库,构建一个基于事件驱动的异步TCP服务器,处理网络连接和数据传输。
环境准备
确保安装了Boost库,并在编译时链接Boost.Asio:
g++ -std=c++11 -o tcp_server tcp_server.cpp -lboost_system -lpthread
实现代码
#include <iostream>
#include <boost/asio.hpp>
#include <memory>
#include <string>
using namespace std;
using namespace boost::asio;
using ip::tcp;// 定义Session类,处理每个客户端连接
class Session : public enable_shared_from_this<Session> {
public:Session(tcp::socket socket) : socket_(move(socket)) {}void start() {doRead();}private:void doRead() {auto self(shared_from_this());socket_.async_read_some(buffer(data, maxLength),[this, self](boost::system::error_code ec, size_t length) {if(!ec) {cout << "Received: " << string(data, length) << endl;doWrite(length);}});}void doWrite(size_t length) {auto self(shared_from_this());async_write(socket_, buffer(data, length),[this, self](boost::system::error_code ec, size_t /*length*/) {if(!ec) {doRead();}});}tcp::socket socket_;enum { maxLength = 1024 };char data[maxLength];
};// 定义Server类,接受并管理客户端连接
class Server {
public:Server(io_service& io_service, short port) :acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),socket_(io_service) {doAccept();}private:void doAccept() {acceptor_.async_accept(socket_,[this](boost::system::error_code ec) {if(!ec) {cout << "New connection from: " << socket_.remote_endpoint() << endl;make_shared<Session>(move(socket_))->start();}doAccept(); // 继续接受下一个连接});}tcp::acceptor acceptor_;tcp::socket socket_;
};int main() {try {io_service io_service;Server server(io_service, 12345);cout << "Server started on port 12345." << endl;io_service.run();}catch(exception& e) {cerr << "Exception: " << e.what() << endl;}return 0;
}
关键注释
#include <boost/asio.hpp> // 引入Boost.Asio库
using namespace boost::asio;
using ip::tcp;// Session类:处理每个客户端连接
class Session : public enable_shared_from_this<Session> {
public:Session(tcp::socket socket) : socket_(move(socket)) {}void start() { // 启动会话,开始读数据doRead();}private:void doRead() { // 异步读取数据auto self(shared_from_this());socket_.async_read_some(buffer(data, maxLength),[this, self](boost::system::error_code ec, size_t length) {if(!ec) {cout << "Received: " << string(data, length) << endl; // 打印接收到的数据doWrite(length); // 回写数据}});}void doWrite(size_t length) { // 异步写数据auto self(shared_from_this());async_write(socket_, buffer(data, length),[this, self](boost::system::error_code ec, size_t /*length*/) {if(!ec) {doRead(); // 继续读取数据}});}tcp::socket socket_; // 客户端套接字enum { maxLength = 1024 };char data[maxLength]; // 数据缓冲区
};// Server类:接受和管理客户端连接
class Server {
public:Server(io_service& io_service, short port) :acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),socket_(io_service) {doAccept();}private:void doAccept() { // 异步接受客户端连接acceptor_.async_accept(socket_,[this](boost::system::error_code ec) {if(!ec) {cout << "New connection from: " << socket_.remote_endpoint() << endl;make_shared<Session>(move(socket_))->start(); // 创建Session处理连接}doAccept(); // 继续接受下一个连接});}tcp::acceptor acceptor_; // 接受器tcp::socket socket_; // 套接字
};int main() {try {io_service io_service; // 创建IO服务Server server(io_service, 12345); // 启动服务器,监听端口12345cout << "Server started on port 12345." << endl;io_service.run(); // 运行IO服务,开始事件循环}catch(exception& e) {cerr << "Exception: " << e.what() << endl;}return 0;
}
说明
通过使用Boost.Asio库,结合事件驱动编程,实现了一个简单的异步TCP服务器。服务器不断监听指定端口,接受新的客户端连接,并通过Session
类处理每个连接的读写操作。整个过程基于异步事件处理,提高了服务器的性能和响应能力。
优化与高级技巧
在构建复杂的事件驱动系统时,除了基本的实现方法外,还需要考虑性能优化和系统设计的高级技巧,以确保系统的高效性和可扩展性。
多线程与事件驱动的结合
将多线程与事件驱动结合,可以充分利用多核CPU的计算能力,提升系统的并发处理能力。然而,在多线程环境下,需要注意线程的同步与资源共享,避免数据竞争和死锁。
示例代码
#include <iostream>
#include <queue>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
using namespace std;// 定义事件类型
typedef function<void()> Event;// 事件循环类,支持多线程
class EventLoop {
public:EventLoop() : running(false) {}// 启动事件循环void start() {running = true;loopThread = thread(&EventLoop::run, this);}// 添加事件到队列void addEvent(Event event) {unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one();}// 停止事件循环void stop() {unique_lock<mutex> lock(mtx);running = false;cv.notify_all();lock.unlock();if(loopThread.joinable()) {loopThread.join();}}~EventLoop() {if(running) {stop();}}private:// 事件循环的主要执行函数void run() {while(running) {Event event;{unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break;event = eventQueue.front();eventQueue.pop();}if(event) {event(); // 执行事件}}}queue<Event> eventQueue; // 事件队列mutex mtx; // 互斥锁condition_variable cv; // 条件变量bool running; // 是否运行事件循环thread loopThread; // 事件循环线程
};// 示例事件处理函数
void handleEvent(int id) {cout << "Handling Event ID: " << id << " in thread " << this_thread::get_id() << endl;
}int main() {EventLoop loop;loop.start();// 主线程添加事件for(int i = 1; i <= 5; ++i) {loop.addEvent([i]() {handleEvent(i);this_thread::sleep_for(chrono::milliseconds(500)); // 模拟处理时间});}// 模拟延迟后停止事件循环this_thread::sleep_for(chrono::seconds(3));loop.stop();return 0;
}
输出结果
Handling Event ID: 1 in thread 140737353607680
Handling Event ID: 2 in thread 140737353607680
Handling Event ID: 3 in thread 140737353607680
Handling Event ID: 4 in thread 140737353607680
Handling Event ID: 5 in thread 140737353607680
关键注释
class EventLoop {
public:void start() { // 启动事件循环,创建事件循环线程running = true;loopThread = thread(&EventLoop::run, this);}void addEvent(Event event) { // 添加事件到队列并通知事件循环unique_lock<mutex> lock(mtx);eventQueue.push(event);cv.notify_one();}void stop() { // 停止事件循环,等待线程结束unique_lock<mutex> lock(mtx);running = false;cv.notify_all(); // 通知所有等待线程lock.unlock();if(loopThread.joinable()) {loopThread.join();}}private:void run() { // 事件循环的主要执行函数while(running) {Event event;{unique_lock<mutex> lock(mtx);// 等待直到有事件或停止信号cv.wait(lock, [this]() { return !eventQueue.empty() || !running; });if(!running && eventQueue.empty()) break; // 如果停止且队列为空,退出循环event = eventQueue.front(); // 获取下一个事件eventQueue.pop();}if(event) {event(); // 执行事件}}}queue<Event> eventQueue; // 事件队列mutex mtx; // 互斥锁保护队列condition_variable cv; // 条件变量用于事件通知bool running; // 事件循环是否在运行thread loopThread; // 事件循环线程
};void handleEvent(int id) { // 事件处理函数cout << "Handling Event ID: " << id << " in thread " << this_thread::get_id() << endl;
}int main() {EventLoop loop;loop.start(); // 启动事件循环for(int i = 1; i <= 5; ++i) { // 主线程添加事件loop.addEvent([i]() { // Lambda表达式作为回调handleEvent(i);this_thread::sleep_for(chrono::milliseconds(500)); // 模拟处理时间});}this_thread::sleep_for(chrono::seconds(3)); // 延迟3秒,确保所有事件处理完成loop.stop(); // 停止事件循环return 0;
}
高效的事件循环设计
设计高效的事件循环,需要考虑以下几点:
- 事件队列的高效管理:使用适当的数据结构,如
std::queue
、std::deque
,确保事件的快速入队和出队。 - 避免阻塞操作:事件处理函数应尽量避免阻塞,防止事件循环被长时间挂起。
- 优先级处理:对于重要事件,可以设计优先级机制,确保高优先级事件优先处理。
- 多线程分工:结合多线程机制,分担事件处理的负载,提高并发处理能力。
使用事件队列提升性能
事件队列是事件驱动编程中核心的组件,通过事件队列,事件循环可以高效地管理和调度事件。
示例代码
#include <iostream>
#include <queue>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;// 定义事件类型
typedef function<void()> Event;// 事件队列类
class EventQueue {
public:// 添加事件到队列void enqueue(Event event) {unique_lock<mutex> lock(mtx);queue.push(event);cv.notify_one(); // 通知等待的线程有新事件}// 从队列中获取事件,若队列为空则等待Event dequeue() {unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() { return !queue.empty() || stopFlag; });if(stopFlag && queue.empty()) return nullptr;Event event = queue.front();queue.pop();return event;}// 停止事件队列void stop() {unique_lock<mutex> lock(mtx);stopFlag = true;cv.notify_all(); // 通知所有等待的线程}private:queue<Event> queue; // 事件队列mutex mtx; // 互斥锁condition_variable cv; // 条件变量bool stopFlag = false; // 是否停止
};// 事件循环函数
void eventLoop(EventQueue& eq) {while(true) {Event event = eq.dequeue(); // 获取事件if(!event) break; // 退出条件event(); // 执行事件}
}int main() {EventQueue eq;// 启动事件循环线程thread loopThread(eventLoop, ref(eq));// 添加事件for(int i = 1; i <= 5; ++i) {eq.enqueue([i]() {cout << "Processing Event " << i << " in thread " << this_thread::get_id() << endl;this_thread::sleep_for(chrono::milliseconds(300)); // 模拟处理时间});}// 添加退出事件eq.enqueue(nullptr); // 使用空事件作为退出信号// 等待事件循环线程结束loopThread.join();return 0;
}
输出结果
Processing Event 1 in thread 140737353607680
Processing Event 2 in thread 140737353607680
Processing Event 3 in thread 140737353607680
Processing Event 4 in thread 140737353607680
Processing Event 5 in thread 140737353607680
关键注释
class EventQueue {
public:void enqueue(Event event) { // 添加事件到队列unique_lock<mutex> lock(mtx);queue.push(event);cv.notify_one(); // 通知等待的线程}Event dequeue() { // 从队列中获取事件unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() { return !queue.empty() || stopFlag; }); // 等待直到有事件或停止信号if(stopFlag && queue.empty()) return nullptr; // 如果停止且队列为空,返回空事件Event event = queue.front();queue.pop();return event;}void stop() { // 停止事件队列,通知所有等待线程unique_lock<mutex> lock(mtx);stopFlag = true;cv.notify_all();}private:queue<Event> queue; // 事件队列mutex mtx; // 互斥锁保护队列condition_variable cv; // 条件变量用于事件通知bool stopFlag = false; // 是否停止
};void eventLoop(EventQueue& eq) { // 事件循环函数while(true) {Event event = eq.dequeue(); // 获取事件if(!event) break; // 如果事件为空,退出循环event(); // 执行事件}
}int main() {EventQueue eq;thread loopThread(eventLoop, ref(eq)); // 启动事件循环线程for(int i = 1; i <= 5; ++i) { // 添加5个事件eq.enqueue([i]() { // 使用Lambda表达式作为回调cout << "Processing Event " << i << " in thread " << this_thread::get_id() << endl;this_thread::sleep_for(chrono::milliseconds(300)); // 模拟事件处理时间});}eq.enqueue(nullptr); // 添加一个空事件作为停止信号loopThread.join(); // 等待事件循环线程结束
}
避免常见的事件处理陷阱
在事件驱动编程中,常见的陷阱包括:
- 回调地狱:过多嵌套回调函数,导致代码难以理解和维护。
- 资源泄漏:事件处理过程中,未正确释放资源,导致内存泄漏或其他资源耗尽。
- 线程安全问题:在多线程环境下,未正确同步共享资源,导致数据竞争或死锁。
- 阻塞事件循环:在事件处理函数中执行长时间的阻塞操作,影响整体系统的响应能力。
通过良好的代码设计和适当的工具,可以有效避免这些问题。
现代C++中的事件驱动编程工具与库
现代C++提供了多种工具和库,帮助开发者更高效地实现事件驱动编程。
Boost.Asio
Boost.Asio是一个跨平台的C++库,用于编写网络和底层I/O应用程序。它提供了异步I/O操作的支持,是构建高性能事件驱动系统的重要工具。
示例代码
前文案例四已详细介绍如何使用Boost.Asio构建异步TCP服务器。
Qt框架的事件系统
Qt是一个跨平台的C++框架,广泛应用于GUI应用开发。Qt拥有强大的事件循环和信号槽(Signal-Slot)机制,极大地简化了事件驱动编程。
示例代码
#include <QCoreApplication>
#include <QObject>
#include <QTimer>
#include <iostream>
using namespace std;// 定义一个类,拥有一个槽函数
class Worker : public QObject {Q_OBJECT
public slots:void onTimeout() { // 槽函数,用于响应超时事件cout << "Timeout event received." << endl;}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);Worker worker;// 创建一个定时器QTimer timer;QObject::connect(&timer, &QTimer::timeout, &worker, &Worker::onTimeout);timer.start(1000); // 每1000毫秒(1秒)触发一次事件return app.exec(); // 进入事件循环
}#include "main.moc"
关键注释
class Worker : public QObject {Q_OBJECT
public slots:void onTimeout() { // 槽函数,响应Qt的timeout信号cout << "Timeout event received." << endl;}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv); // 创建Qt核心应用Worker worker;QTimer timer; // 创建一个定时器QObject::connect(&timer, &QTimer::timeout, &worker, &Worker::onTimeout); // 连接timeout信号到槽函数timer.start(1000); // 启动定时器,1秒触发一次return app.exec(); // 进入Qt事件循环
}
说明
Qt的信号槽机制是一种类型安全、强大的回调系统,允许对象之间通过信号和槽进行通信,极大地简化了事件驱动编程的实现。
libuv与Node.js的事件驱动模型
libuv是一个跨平台的异步I/O库,Node.js就是基于libuv构建的。虽然libuv主要用于C语言,但它的设计思想和事件驱动模型对C++事件驱动编程也有借鉴意义。
总结
事件驱动编程作为一种灵活、高效的编程范式,在C++应用开发中扮演着重要角色。通过理解事件驱动编程的基本概念,掌握回调函数、观察者模式、事件循环等基本实现方法,并结合Boost.Asio、Qt等现代C++库,开发者可以构建高性能、响应迅速的应用程序。
在实际开发中,需注意事件循环的高效设计,避免阻塞操作,合理管理多线程环境下的同步与资源共享。通过持续学习和实践,开发者能深入掌握C++事件驱动编程的技巧,打造出高效、稳定、可扩展的系统。
参考资料
- Boost.Asio官方文档
- Qt官方文档 - 信号与槽
- C++11标准文档
- Effective Modern C++ - Scott Meyers
- C++ Concurrency in Action - Anthony Williams
- libuv官方文档
- Design Patterns: Elements of Reusable Object-Oriented Software - Erich Gamma等
- Observer Pattern in C++ with Practical Example
- Mastering Boost.Asio
- Programming with Qt - Tutorial
标签
C++、事件驱动、回调函数、观察者模式、事件循环、Boost.Asio、Qt框架、异步编程、多线程、信号槽
版权声明
本文版权归作者所有,未经允许,请勿转载。
相关文章:
C++事件驱动编程从入门到实战:深入理解与高效应用
C事件驱动编程从入门到实战:深入理解与高效应用 在现代软件开发中,事件驱动编程(Event-Driven Programming)作为一种流行的编程范式,被广泛应用于图形用户界面(GUI)、网络通信、游戏开发等众多…...
问题 | MATLAB比Python更有优势的特定领域
以下是关于MATLAB在特定领域相较于Python的优势的详细分析,结合其核心功能、行业应用及技术特性展开论述: 一、科学研究与工程计算 1. 数值计算的高效性 MATLAB的核心设计围绕矩阵运算展开,其底层对线性代数和数值计算进行了深度优化。例如…...
黑马商城项目(三)微服务
一、单体架构 测试高并发软件 二、微服务 三、SpringCloud 四、微服务拆分 黑马商城模块: 服务拆分原则: 拆分服务: 独立project: maven聚合: 拆分案例: 远程调用: package com.hmall.cart.…...
Qt界面卡住变慢的解决方法
本质原因: 当Qt界面出现卡顿或无响应时,通常是因为主线程(GUI线程)被耗时操作阻塞。 完全忘了。。。 Qt Creater解决方法 1. 定位耗时操作 目标:找到阻塞主线程的代码段。 方法: 使用QElapsedTimer测量代码执行时间…...
Flutter的原理及美团的实践(下)
Flutter的原理及性能实践 Flutter和原生性能对比 虽然使用原生实现(左)和Flutter实现(右)的全品类页面在实际使用过程中几乎分辨不出来: 但是我们还需要在性能方面有一个比较明确的数据对比。 我们最关心的两个页面…...
时序预测 | Matlab实现基于VMD-WOA-ELM和VMD-ELM变分模态分解结合鲸鱼算法优化极限学习机时间序列预测
时序预测 | Matlab实现基于VMD-WOA-ELM和VMD-ELM变分模态分解结合鲸鱼算法优化极限学习机时间序列预测 目录 时序预测 | Matlab实现基于VMD-WOA-ELM和VMD-ELM变分模态分解结合鲸鱼算法优化极限学习机时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab…...
【云安全】云原生- K8S IngressNightmare CVE-2025-1974(漏洞复现完整教程)
漏洞原理 CVE-2025-1974: The IngressNightmare in Kubernetes | Wiz Blog 分两方面: a、配置注入过程 构造一个恶意的Ingress资源,其中注入ssl_engine指令指向恶意共享库向准入控制器验证端点(AdmissionWebhook)发送Admissio…...
Tomcat与Servlet(2)
上篇文章: Tomcat与Servlethttps://blog.csdn.net/sniper_fandc/article/details/147278469?fromshareblogdetail&sharetypeblogdetail&sharerId147278469&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 上篇文章介绍了To…...
在高数据速度下确保信号完整性的 10 个关键策略
随着越来越多的传感器连接到系统,需要快速、可靠和安全地传输更多数据,对带宽和设计复杂性的需求也在增加。优先考虑的是确保从 A 发送到 B 的信号不会失真。 确保信号完整性 对于设计依赖于持续准确数据流的数据密集型应用程序的工程师来说,…...
2025华中杯数学建模B题完整分析论文(共42页)(含模型、数据、可运行代码)
2025华中杯大学生数学建模B题完整分析论文 目录 一、问题重述 二、问题分析 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1解析 4.1.2问题1模型建立 4.1.3问题1样例代码(仅供参考) 4.1.4问题1求解结果(仅供参考&am…...
UE5 自带的视频播放器
文章目录 文件夹准备添加一个文件媒体源方法1方法2 添加一个视频播放器播放视频直接播放使用网格体播放使用UI播放 播放视频的音乐媒体播放器常用的节点设置循环是用绝对路径播放视频,视频无需导入注册播放完成事件 文件夹准备 视频必须被放在Content/Moveis文件下…...
是德科技E5080B网络分析仪深度评测:5G/车载雷达测试实战指南
是德科技E5080B网络分析仪(ENA系列)是一款高性能射频测试仪器,广泛应用于通信、航空航天、半导体等领域,以下是其核心功能详解: 一、核心测试功能 多参数网络分析 S参数测量:支持全双端口S参数测试…...
javaSE————网络编程套接字
网络编程套接字~~~~~ 好久没更新啦,蓝桥杯爆掉了,从今天开始爆更嗷; 1,网络编程基础 为啥要有网络编程呢,我们进行网络通信就是为了获取丰富的网络资源,说实话真的很神奇,想想我们躺在床上&a…...
力扣349 == 两个数组交集的两种解法
目录 解法一:利用 Set 特性高效去重 解法二:双重遍历与 Set 去重 方法对比与总结 关键点总结 题目描述 给定两个整数数组 nums1 和 nums2,要求返回它们的交集。输出结果中的每个元素必须是唯一的,且顺序不限。 示例 输入&…...
笔试专题(十)
文章目录 对称之美(双指针)题解代码 连续子数组最大和(线性dp)题解代码 最长回文子序列(区间dp)题解代码 对称之美(双指针) 题目链接 题解 1. 双指针 2. 用left标记左边的字符串…...
YOLOv12即插即用---RFAConv
1.模块介绍 接受域注意卷积(RFAConv):更聪明地感知空间特征 在传统卷积神经网络中,卷积核参数的共享机制虽有效提升了模型的泛化能力与计算效率,但却忽略了不同空间位置特征在感知范围(即接受域)内的重要性差异。为此,我们提出了一种更具感知能力的模块 —— 接受域注…...
使用datax通过HbaseShell封装writer和reader同步hbase数据到hbase_踩坑_细节总结---大数据之DataX工作笔记008
最近在做大数据相关功能,有个需求,使用datax同步hbase到hbase中,其中还是有很多细节值得记录: 首先来看一下datax的源码中,如果你使用phoenix创建的表,那么 你就需要使用对应的hbase带有sql字样的,reader和writer. 然后如果你使用datax-web来进行测试的,那么,他默认使用的是h…...
Python解决“小D的abc字符变换”问题
小D的“abc”变换问题 问题描述测试样例解题思路代码 问题描述 小D拿到了一个仅由 “abc” 三种字母组成的字符串。她每次操作会对所有字符同时进行以下变换: 将 ‘a’ 变成 ‘bc’ 将 ‘b’ 变成 ‘ca’ 将 ‘c’ 变成 ‘ab’ 小D将重复该操作 k 次。你的任务是输…...
C++学习:六个月从基础到就业——面向对象编程:重载运算符(下)
C学习:六个月从基础到就业——面向对象编程:重载运算符(下) 本文是我C学习之旅系列的第十三篇技术文章,是面向对象编程中运算符重载主题的下篇。本篇文章将继续深入探讨高级运算符重载技术、特殊运算符、常见应用场景和…...
电压模式控制学习
电压模式控制 在开关电源中,大的可分为三大控制模式,分别是电压模式控制,电流模式控制,迟滞模式控制。今天简要介绍下电压模式控制的优缺点。 原理 架构图如下 如图所示,电压模式控制可以分为三部分:误…...
vue3 Ts axios 封装
vue3 Ts axios 封装 axios的封装 import axios, { AxiosError, AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig, AxiosHeaders } from axios import qs from qs import { config } from ./config import { ElMessage } from element-plus// …...
GPT,Bert类模型对比
以下是对 BERT-base、RoBERTa-base、DeBERTa-base 和 DistilBERT-base 四个模型在参数量、训练数据、GPU 内存占用、性能表现以及优缺点方面的对比: 模型参数量与训练数据 模型参数量训练数据量BERT-base110MBookCorpus(8亿词) 英文维基百科…...
3.Rust + Axum 提取器模式深度剖析
摘要 深入解读 Rust Axum 提取器模式,涵盖内置提取器及自定义实现。 一、引言 在 Rust 的 Web 开发领域,Axum 作为一款轻量级且高效的 Web 框架,为开发者提供了强大的功能。其中,提取器(Extractor)模式…...
Dify vs n8n vs RAGFlow:2025年AI应用与自动化工作流平台的终极对决
我将为大家整理一份关于 Dify、n8n 和 Ragflow 的最新研究分析,涵盖以下六个方面:功能对比、应用场景、架构设计、集成能力、和使用门槛。我会尽可能引用其官方文档、GitHub 仓库以及社区讨论等权威信息来源。 我整理好后会第一时间通知你查看。 1.Dify、n8n 和 RAGFlow 最新…...
ffmpeg无损转格式的命令行
将ffmpeg.exe拖入命令行窗口 c:\users\zhangsan>D:\ffmpeg-2025-03-11\bin\ffmpeg.exe -i happy.mp4 -c:v copy -c:a copy 格式转换后.mkv -c:v copy 仅做拷贝视频,不重新编码 -c:a copy 仅做拷贝音频 ,不重新编码...
Flutter 常用命令
1、创建项目 flutter create <项目名称> 示例: flutter create my_app 1.1 参数说明 --org:设置包名(默认 com.example) flutter create --org com.yourcompany my_app -a/-i:指定语言(Kotlin…...
【零基础】基于DeepSeek-R1与Qwen2.5Max的行业洞察自动化平台
自动生成行业报告,通过调用两个不同的大模型(DeepSeek 和 Qwen),完成从行业趋势分析到结构化报告生成的全过程。 完整代码:https://mp.weixin.qq.com/s/6pHi_aIDBcJKw1U61n1uUg 🧠 1. 整体目的与功能 该脚本实现了一个名为 ReportGenerator 的类,用于: 调用 DeepSe…...
UE5 关卡序列
文章目录 介绍创建一个关卡序列编辑动画添加一个物体编辑动画时间轴显示秒而不是帧时间轴跳转到一个确定的时间时间轴的显示范围更改关键帧的动画插值方式操作多个关键帧 播放动画 介绍 类似于Unity的Animation动画,可以用来录制场景中物体的动画 创建一个关卡序列…...
1.凸包、极点、极边基础概念
目录 1.凸包 2.调色问题 3.极性(Extrem) 4.凸组合(Convex Combination) 5.问题转化(Strategy)编辑 6.In-Triangle test 7.To-Left-test 8.极边(Extream Edges) 1.凸包 凸包就是上面蓝色皮筋围出来的范围 这些钉子可以转换到坐标轴中࿰…...
MahApps.Metro:专为 WPF 应用程序设计的 UI 框架
推荐一个WPF 应用程序设计的 UI 框架,方便我们快速构建美观、流畅的应用程序。 01 项目简介 MahApps.Metro 是一个开源的 UI 框架,它可以让开发者快速构建现代化、美观的 WPF 应用程序。 提供了一套完整的 UI 组件和主题,支持流畅的动画效…...
【LangChain4j快速入门】5分钟用Java玩转GPT-4o-mini,Spring Boot整合实战!| 附源码
【LangChain4j快速入门】5分钟用Java玩转GPT-4o-mini,Spring Boot整合实战! 前言:当Java遇上大模型 在AI浪潮席卷全球的今天,Java开发者如何快速拥抱大语言模型?LangChain4j作为专为Java打造的AI开发框架,…...
乐言科技:云原生加速电商行业赋能,云消息队列助力降本 37%
深耕 AI SaaS,助力数万电商客户数智化转型 上海乐言科技股份有限公司(以下简称“乐言科技”,官网:https://www.leyantech.com/)自 2016 年成立以来,专注于利用自然语言处理和深度学习等核心 AI 技术&#…...
vscode构建简单编译和调试环境
一、设置环境变量 将bin目录路径(如D:\DevTools\mingw64\bin)加入系统环境变量PATH34 二、VS Code插件配置 核心插件安装 C/C(微软官方扩展,提供语法高亮、智能提示)Code Runner࿰…...
STM32控制DRV8825驱动42BYGH34步进电机
最近想玩一下人工智能,然后买了个步进电机想玩一下,刚到了一脸懵逼,发现驱动器20多块,有点超预算,然后整了个驱动板,方便自己画线路板,经过各种搜索,终于转起来了,记录一…...
系统清理专家,一键释放磁盘空间!
打工人们你们好!这里是摸鱼 特供版~ 今天给大家带来一款超实用的系统清理工具——Glary Disk Cleaner,帮助你快速清理系统中的垃圾文件,释放磁盘空间,提升系统运行速度! 推荐指数:★★★★★ 软件简介 G…...
识别法院PDF文件特定字段并插入数据库【正则表达式+本地化部署】
pdf解析法院协助单特定字段,开源项目,结合若依项目进行开发,不连互联网,本地开发部署,前端使用vue3技术,后端用若依分离版spring botot技术,实现将pdf法院协助执行通知书中的特定字段如:时间、文…...
探索智能体开发新范式:Cangjie Magic深度解析与实践指南
引言:智能体开发的新纪元 2025年3月,仓颉社区开源了基于仓颉编程语言原生构建的LLM Agent开发平台——Cangjie Magic,为智能体开发领域带来了革命性的变革。作为一名长期关注AI技术发展的开发者,我有幸在第一时间体验了这一创新平…...
计算机网络 - UDP协议
通过一些问题来讨论 UDP 协议 什么是 UDP?举几个应用了 UDP 协议的例子UDP 与 TCP 有啥区别?(PS:介绍三四个就可以了,不用说太多)具体 UDP 是不可靠的,那你觉得如何实现一个可靠的 UDP &#x…...
阿里云ECS访问不了
使用xshell连接阿里云ECS,下载nginx,然后启动 sudo systemctl start nginx 查看状态是 sudo systemctl status nginx 输入公网ip访问实例访问不到,出现 可以查看阿里云实例中的安全组,是否对外开放了80端口和443端口 添加入方向…...
Starrocks添删改查数据(二)
先安装好Starrocks,参考:Starrocks入门(二)_backend node not found. check if any backend node -CSDN博客 1、建立库 建库成功。 2、建立表 参考:表概览 | StarRocks 执行如下SQL: CREATE TABLE user_…...
RT-Thread学习笔记(一)
RT-Thread学习笔记 AIotMMUCPU架构RT-Thread版本工程创建时钟配置FinSH内核RT-Thread内核启动流程 RT-Thread是一个组件完整丰富、高度可伸缩、简易开发、超低功耗、高安全性的物联网操作系统 全称Real Time Thread AIot AIot: Artificial Intelligence of Things…...
【源码】30个Python小游戏
下载链接:https://github.com/pyGuru123/Python-Games 本站下载链接:【免费】源码30个Python小游戏资源-CSDN文库 包含:飞机大战、愤怒的墙、圆弧冲刺、行星游戏、弹跳的球、汽车避障、洞穴物语、愤怒的小鸟、丛林探险、扫雷、俄罗斯方块、…...
【Web前端技术】第二节—HTML标签(上)
hello!好久不见—— 做出一个属于自己的网站! 云边有个稻草人-个人主页 Web前端技术—本篇文章所属专栏 目录 一、HTML 语法规范 1.1 基本语法概述 1.2 标签关系 二、HTML 基本结构标签 2.1 第一个 HTML 网页 2.2 基本结构标签总结 三、网页开发…...
Android开发协调布局滑动悬停
Android开发协调布局滑动悬停 直接给个xml,防止下次忘了怎么写。 <?xml version"1.0" encoding"utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android"http://schemas.android.com/apk/res/android…...
R语言简介与下载安装
1.R语言简介与下载安装 R语言其诞生于新西兰奥克兰大学,由Ross Ihaka 和Robert Gentleman开发,属于商业软件S语言的替代品;R语言是一款开源的编程类工具,专门用于数据清洗、整理、统计分析、可视化以及数据挖掘等方面,…...
CGAL边折叠edge_collapse的问题
使用edge_collapse对一个模型简化,之后回收垃圾,collect_garbage 处理之前的顶点和三角形数量: number_of_vertices: 955730 number_of_faces: 1903410 num_vertices: 955730 num_faces: 1903410 处理之后的顶点和三角形数量:…...
2025 全球分布式云大会演讲实录 | 沈建发:智启边缘,畅想未来:边缘计算新场景落地与 Al 趋势新畅想
4 月 9 日,2025 全球分布式云大会暨 AI 基础设施大会在深圳成功举办,火山引擎边缘云产品解决方案高级总监沈建发出席并以《智启边缘,畅想未来:边缘计算新场景落地与 Al 趋势新畅想》为主题,分享了边缘计算在 AI 技术趋…...
【ELF2学习板】OpenCL程序测试
目录 引言 OpenCL简介 主要特点 编程模型 应用场景 测试程序 代码说明 构建编译环境 头文件 库文件 程序编译 测试结果 结语 引言 ELF2开发板采用的是RK3588处理器,它是瑞芯微推出的一款高性能 SoC。RK3588 集成了 ARM Mali-G610 MP4 GPU,…...
EtherCAT转ProfiNet边缘计算网关配置优化:汽车制造场景下PLC与机器人协同作业案例
1.行业背景与需求分析 智能汽车焊装车间是汽车制造的核心工艺环节,某德国豪华品牌在其上海MEB工厂新建的焊装车间中,采用西门子S7-1500PLC作为ProfiNet主站,负责整线协调与质量追溯;同时部署KUKAKR1500Titan机器人(Eth…...
AI 推理与训练优化的核心理论体系建构及关键技术分析框架
AI 推理与训练优化的核心理论体系建构及关键技术分析框架 一、推理加速的动态系统理论建模与算法设计 (一)基于MDP的动态计算图理论 生物启发的决策框架:模拟灵长类视觉系统的注意力分配机制,构建马尔可夫决策过程(M…...