Muduo网络库介绍
1.Reactor介绍
1.回调函数
**回调(Callback)**是一种编程技术,允许将一个函数作为参数传递给另一个函数,并在适当的时候调用该函数
1.工作原理
-
定义回调函数
-
注册回调函数
- 触发回调
2.优点
-
异步编程
-
回调函数允许在事件发生时执行特定的逻辑,而无需阻塞主线程,特别适合实现异步编程。
-
例如,在网络编程中,当数据可读或可写时调用回调函数,而无需阻塞等待。
-
-
事件驱动
-
回调函数是事件驱动编程的核心机制,可以高效地处理事件,提高系统的响应速度和吞吐量。
-
例如,在 GUI 编程中,按钮点击事件会触发回调函数。
-
-
代码复用
-
回调函数可以独立定义和复用,提高了代码的可复用性和可维护性。
-
例如,同一个回调函数可以用于多个事件处理。
-
3.缺点
-
回调地狱: 当回调函数嵌套过深时,代码结构会变得混乱,难以理解和维护,这种现象被称为“回调地狱”。
-
错误处理复杂
-
回调函数中的错误处理逻辑需要分散在各个回调函数中,增加了错误处理的复杂性。
-
例如,每个回调函数都需要单独处理错误。
-
-
调试困难
-
回调函数的调用链可能很长,调试时难以跟踪回调函数的执行顺序和上下文。
-
3.回调函应用
1. Linux 信号捕捉
在 Linux 系统中,信号(Signal)是一种软件中断机制,用于通知进程发生了某些事件。进程可以通过信号处理函数(即回调函数)来响应这些事件。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 定义信号处理函数(回调函数)
void signal_handler(int sig) {printf("Received signal %d\n", sig);
}int main() {// 注册信号处理函数signal(SIGINT, signal_handler); // 捕捉 Ctrl+C 信号signal(SIGTERM, signal_handler); // 捕捉 kill 信号printf("Process ID: %d\n", getpid());printf("Press Ctrl+C to send SIGINT signal\n");// 无限循环,等待信号while (1) {sleep(1);}return 0;
}
-
定义回调函数:
signal_handler
是一个回调函数,用于处理信号事件。它接收一个参数sig
,表示接收到的信号编号。 -
注册回调函数:使用
signal
函数将特定信号(如SIGINT
、SIGTERM
)与回调函数关联起来。当进程接收到这些信号时,系统会自动调用注册的回调函数。 -
触发回调:当进程接收到指定的信号时,操作系统会中断当前执行的代码,调用注册的回调函数。回调函数执行完成后,进程继续执行。
2. 多线程线程创建
在多线程编程中,线程创建时通常需要指定一个回调函数,该函数在线程启动时被调用。
#include <iostream>
#include <thread>// 定义线程回调函数
void thread_function(int id) {std::cout << "Thread " << id << " is running\n";
}int main() {// 创建线程并指定回调函数std::thread t1(thread_function, 1);std::thread t2(thread_function, 2);// 等待线程完成t1.join();t2.join();return 0;
}
-
定义回调函数:
thread_function
是一个回调函数,用于在线程启动时执行。它接收一个参数id
,表示线程的编号。 -
创建线程并注册回调函数:使用
std::thread
构造函数创建线程时,将回调函数和参数传递给线程对象。线程启动时会自动调用该回调函数。 -
触发回调:线程启动时,系统会调用注册的回调函数,并将线程参数传递给它。
3. Qt 信号槽机制
Qt 是一个跨平台的 C++ 应用程序开发框架,广泛用于开发图形用户界面(GUI)应用程序。Qt 的信号槽机制是一种基于回调的事件处理机制。
#include <QApplication>
#include <QPushButton>// 定义槽函数(回调函数)
void buttonClicked() {std::cout << "Button clicked!\n";
}int main(int argc, char *argv[]) {QApplication app(argc, argv);QPushButton button("Click Me");button.show();// 连接信号和槽QObject::connect(&button, &QPushButton::clicked, buttonClicked);return app.exec();
}
-
定义槽函数:
buttonClicked
是一个槽函数(回调函数),用于处理按钮点击事件。 -
连接信号和槽:使用
QObject::connect
函数将按钮的clicked
信号与槽函数关联起来。当按钮被点击时,系统会自动调用槽函数。 -
触发回调:当用户点击按钮时,按钮会发出
clicked
信号,Qt 的事件循环会检测到该信号并调用注册的槽函数。
4. 可调用对象包装器绑定器
在 C++ 中,可以使用 std::function
和 std::bind
来创建可调用对象包装器和绑定器,从而实现更灵活的回调机制。(不需要函数指针,将函数包装成可调用对象)
#include <iostream>
#include <functional>
#include <thread>// 定义回调函数
void callback_function(int a, int b) {std::cout << "Callback called with arguments: " << a << " and " << b << std::endl;
}int main() {// 使用 std::bind 绑定回调函数和参数auto bound_callback = std::bind(callback_function, 10, 20);// 使用 std::function 包装回调函数std::function<void()> callback = bound_callback;// 在线程中调用回调函数std::thread t(callback);t.join();return 0;
}
-
定义回调函数:
callback_function
是一个回调函数,接收两个参数a
和b
。 -
绑定回调函数和参数:使用
std::bind
将回调函数和参数绑定在一起,生成一个可调用对象。 -
包装回调函数:使用
std::function
将绑定后的可调用对象包装起来,使其可以作为回调函数使用。 -
触发回调:在新线程中调用包装后的回调函数。
2.Reactor 模型
基于 Reactor 模型是一种高效的事件驱动编程模式,广泛应用于网络编程和并发处理。它通过监听事件(如 I/O 事件、定时事件等)并触发相应的回调函数来处理这些事件,从而实现高效的并发处理。Reactor 模型的核心思想是将事件处理逻辑与事件监听逻辑分离,使得系统能够高效地处理大量并发事件。
1..Reactor 模型的核心组件
-
事件分发器(Event Demultiplexer)
-
负责监听和分发事件。它通常使用操作系统提供的 I/O 多路复用机制(如
select
、poll
、epoll
等)来同时监听多个文件描述符(如套接字)上的事件。 -
当某个文件描述符上有事件发生时(如新连接、数据可读、数据可写等),事件分发器会将事件通知给相应的事件处理器。
-
-
事件处理器(Event Handler)
-
是与特定事件相关联的回调函数或对象。当事件分发器检测到某个事件时,会调用相应的事件处理器来处理该事件。
-
事件处理器通常包括以下几种类型:
-
接受连接处理器(Acceptor):负责处理新连接事件,通常用于服务器端接受客户端的连接请求。
-
读事件处理器(Reader):负责处理数据可读事件,从套接字中读取数据。
-
写事件处理器(Writer):负责处理数据可写事件,将数据写入套接字。
-
定时器处理器(Timer Handler):负责处理定时事件,用于实现定时任务。
-
-
-
事件循环(Event Loop)
-
是 Reactor 模型的运行时核心,负责驱动整个事件处理流程。它通常是一个无限循环,持续监听事件并调用相应的事件处理器。
-
事件循环的主要步骤包括:
-
调用事件分发器,获取已经就绪的事件。
-
遍历就绪事件列表,调用每个事件对应的事件处理器。
-
处理完所有事件后,继续循环监听新的事件。
-
-
2.
3.Reactor 模型的优点
-
高并发处理能力
-
通过事件驱动和回调机制,Reactor 模型可以高效地处理大量并发事件,而无需为每个连接创建一个线程或进程。
-
特别适合处理高并发的网络服务,如 Web 服务器、聊天服务器等。
-
-
资源利用率高
-
事件分发器使用 I/O 多路复用机制,可以同时监听多个文件描述符,减少了系统资源的浪费。
-
事件处理器通常是非阻塞的,不会阻塞事件循环,从而提高了系统的响应速度和吞吐量。
-
-
代码结构清晰
-
Reactor 模型将事件处理逻辑与事件监听逻辑分离,使得代码结构更加清晰,易于维护和扩展。
-
事件处理器可以独立开发和测试,提高了代码的可复用性。
-
4.Reactor 模型的缺点
-
回调地狱
-
由于事件处理逻辑是通过回调函数实现的,当事件处理逻辑复杂时,可能会导致回调嵌套过深,形成“回调地狱”,使代码难以理解和维护。
-
例如,多个异步操作的嵌套回调可能会导致代码结构混乱。
-
-
错误处理复杂
-
在事件驱动的编程模型中,错误处理逻辑需要分散在各个事件处理器中,增加了错误处理的复杂性。
-
例如,网络错误、文件读写错误等需要在每个事件处理器中单独处理。
-
-
不适合 CPU 密集型任务
-
Reactor 模型主要适用于 I/O 密集型任务,对于 CPU 密集型任务,事件循环可能会被阻塞,从而影响系统的性能。
-
例如,计算密集型任务可能会导致事件循环无法及时处理新的事件。
-
5.Reactor 模型的应用场景
Reactor 模型广泛应用于高性能网络编程和并发处理场景,以下是一些典型的应用场景:
-
Web 服务器
-
Web 服务器需要同时处理大量客户端的 HTTP 请求,Reactor 模型可以高效地处理并发请求,提高服务器的吞吐量。
-
例如,Nginx 和 Node.js 都采用了类似的事件驱动模型。
-
-
聊天服务器
-
聊天服务器需要实时处理用户的连接和消息,Reactor 模型可以快速响应用户的输入和消息推送。
-
例如,基于 WebSocket 的聊天服务可以利用 Reactor 模型实现高效的通信。
-
-
游戏服务器
-
游戏服务器需要处理大量玩家的实时交互,Reactor 模型可以高效地处理玩家的输入和游戏逻辑。
-
例如,多人在线游戏服务器可以利用 Reactor 模型实现高并发处理。
-
-
分布式系统
-
分布式系统中的节点需要高效地通信和同步数据,Reactor 模型可以用于实现高效的网络通信。
-
例如,分布式缓存系统和分布式数据库可以利用 Reactor 模型实现高效的节点间通信。
-
6.Reactor 模型的实现示例
以下是一个简单的 Reactor 模型实现示例,使用 C++ 和 epoll
机制:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/epoll.h>
#include <fcntl.h>// 设置文件描述符为非阻塞模式
void setNonBlocking(int fd) {int flags = fcntl(fd, F_GETFL, 0);flags |= O_NONBLOCK;fcntl(fd, F_SETFL, flags);
}// 事件处理器接口
class EventHandler {
public:virtual void handleEvent(int fd) = 0;virtual ~EventHandler() {}
};// Reactor 类
class Reactor {
public:Reactor() : epoll_fd(epoll_create1(0)) {}~Reactor() {close(epoll_fd);}// 注册事件处理器void registerHandler(int fd, EventHandler* handler) {setNonBlocking(fd);struct epoll_event ev;ev.events = EPOLLIN | EPOLLET; // 边缘触发,监听读事件ev.data.ptr = handler;epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);}// 运行事件循环void run() {std::vector<struct epoll_event> events(16);while (true) {int nfds = epoll_wait(epoll_fd, events.data(), events.size(), -1);for (int i = 0; i < nfds; ++i) {EventHandler* handler = static_cast<EventHandler*>(events[i].data.ptr);handler->handleEvent(events[i].data.fd);}}}private:int epoll_fd;
};// 示例事件处理器
class MyEventHandler : public EventHandler {
public:void handleEvent(int fd) override {std::cout << "Event on fd: " << fd << std::endl;// 处理事件逻辑,例如读取数据}
};int main() {Reactor reactor;int fd = 0; // 示例文件描述符,实际应用中可以是套接字MyEventHandler handler;reactor.registerHandler(fd, &handler);reactor.run();return 0;
}
在这个示例中,Reactor
类负责管理事件循环和事件分发器(epoll
),EventHandler
是事件处理器的接口,MyEventHandler
是具体的事件处理器实现。通过调用 registerHandler
方法,可以将文件描述符和事件处理器注册到 Reactor 中,然后运行事件循环来处理事件。
3.为什么Reactor适合高并发
Reactor 模式之所以适合高并发场景,主要是因为它采用了事件驱动的方式,避免了传统多线程/多进程模型的高开销。
在高并发情况下,如果采用每个连接创建一个线程(One Thread Per Connection)的方式,会导致:
-
线程上下文切换开销大。
-
线程资源(如栈、调度等)消耗过多。
-
操作系统管理大量线程的开销增加。
而 Reactor 模型 通过 I/O 多路复用 机制(如 epoll
)实现高效的事件处理,能够支撑大规模连接。
Reactor 适合高并发的关键点
1. 基于 I/O 多路复用,避免阻塞
传统的阻塞 I/O 需要为每个连接创建一个线程来处理 I/O 操作,导致线程资源浪费。而 Reactor 模式使用 epoll/kqueue
这类高效的 I/O 多路复用技术,可以让单线程高效管理上万个连
-
epoll_wait
只需少量线程,即可监听成千上万个连接的事件变化。 -
当某个 socket 可读/可写时,Reactor 仅对其处理,而不会阻塞其他连接。
2. 避免频繁的线程切换
-
传统
One Thread Per Connection
每个请求创建一个线程,线程上下文切换(context switch)是性能瓶颈。 -
Reactor 采用少量线程来管理大量连接,避免了过多的线程切换开销。
对比:
方案 | 线程数 | 线程切换 | 适用场景 |
---|---|---|---|
每连接一个线程 | N (连接数) | 高 | 低并发场景 |
线程池 | M(固定数量) | 中 | 中等并发 |
Reactor (epoll) | 1 或 M(少量) | 低 | 高并发 |
3. 高效的任务分发
Reactor 只负责事件分发,不会阻塞:
-
当有连接可读,Reactor 触发
onMessage()
处理数据。 -
当有新连接,Reactor 触发
onConnection()
处理新连接。 -
实际业务逻辑可以交给工作线程池执行,避免阻塞 Reactor 主线程。
4. 单线程或多线程模式可扩展
-
小规模服务:单线程 Reactor,所有 I/O 和计算在一个线程内完成。
-
大规模服务:多线程 Reactor,主线程负责 I/O,工作线程池处理业务逻辑。
2.Moduo网络库简介
-
开发背景:muduo是陈硕个人开发的TCP网络编程库,主要用于Linux平台。
-
编程模型:它基于Reactor模式,支持多线程。其核心设计是一个线程一个事件循环(one loop per thread),即一个线程只能有一个事件循环(EventLoop),而一个文件描述符(fd)只能由一个线程进行读写。
-
主要特性:
-
使用非阻塞IO和事件驱动。
-
提供了线程池(ThreadPool)来处理耗时的计算任务。
-
支持TCP连接的生命周期管理。
-
提供了丰富的回调机制,用于处理连接建立、消息到达、连接断开等事件。
-
-
适用场景:适用于开发高并发的TCP服务器,将网络I/O与业务代码分开
muduo的主要组件
-
EventLoop:事件循环,负责监听事件并调用对应的回调函数。
-
Poller:事件监听器,负责检测事件是否触发,muduo默认使用epoll实现。
-
TcpServer:用于创建TCP服务器,管理连接和事件循环。
-
TcpConnection:表示一个TCP连接,封装了连接的读写操作。
-
Acceptor:负责接收新连接,并将其分配到子事件循环(subReactor)中。
muduo的优势
-
高性能:基于Linux的epoll机制,能够高效地处理大量并发连接。
-
易用性:提供了简洁的API,方便开发者快速实现网络服务。
-
可扩展性:支持多线程模型,可以根据CPU核心数灵活扩展。
1.Muduo 的特点
1.基于 Reactor 模型
-
采用 epoll(多路复用)实现事件驱动的 I/O 处理。
-
高效的事件循环(
EventLoop
)避免了传统阻塞式编程的缺陷。
2.多线程友好
-
采用 one loop per thread(每个线程一个
EventLoop
)的方式,避免锁争用,提高并发性能。 -
提供
EventLoopThreadPool
,支持多线程调度。
3.非阻塞 + 事件驱动
-
采用 非阻塞套接字 + 边缘触发(ET 模式),降低 CPU 负担,提高吞吐量。
-
配合定时器(
TimerQueue
)支持高精度定时任务。
在网络服务器开发中,经常需要 定时任务,比如:
-
定期清理空闲连接(避免资源浪费)
-
定时发送心跳包(保持连接活跃)
-
任务超时检测(如 HTTP 请求超时)
TimerQueue
主要功能
-
支持 一次性定时任务(只执行一次)
-
支持 周期性定时任务(定期触发)
-
使用
timerfd
触发定时事件,精度高 -
所有定时任务都在
EventLoop
线程中执行,线程安全
4.现代 C++ 设计
-
遵循 RAII 原则,避免资源泄露。
-
使用
boost::noncopyable
防止对象拷贝,提高安全性。 -
提供智能指针(如
std::shared_ptr
)管理连接生命周期,避免悬空指针问题。
5.高效的 Buffer 设计
-
Buffer
类封装了 零拷贝 机制,提高数据读写性能。
零拷贝机制是一种优化技术,旨在减少数据在内存中的拷贝次数,从而提高数据传输的效率。在传统的数据传输过程中,数据通常需要在多个缓冲区之间进行多次拷贝,这不仅增加了 CPU 的负担,还可能导致性能瓶颈。零拷贝机制通过减少这些不必要的拷贝操作,显著提高了数据传输的性能。
1.传统数据传输方式
在传统的数据传输中,数据通常需要经过多次拷贝。例如,从磁盘读取数据并发送到网络,可能涉及以下步骤:
-
从磁盘读取数据到内核缓冲区:
-
数据从磁盘读取到内核的缓冲区。
-
这一步通常由
read
系统调用完成。
-
-
从内核缓冲区拷贝到用户空间缓冲区:
-
数据从内核缓冲区拷贝到用户空间的缓冲区。
-
这一步通常由
read
系统调用完成。
-
-
从用户空间缓冲区拷贝到内核缓冲区:
-
数据从用户空间的缓冲区拷贝回内核缓冲区。
-
这一步通常由
write
系统调用完成。
-
-
从内核缓冲区发送到网络:
-
数据从内核缓冲区发送到网络。
-
这一步通常由
write
系统调用完成。
-
这种传统的数据传输方式涉及多次数据拷贝,增加了 CPU 的负担,降低了性能。
2.零拷贝机制的优势
零拷贝机制通过减少数据在内存中的拷贝次数,显著提高了数据传输的效率。具体优势包括:
-
减少 CPU 负担:
-
减少了数据在内核空间和用户空间之间的拷贝操作,降低了 CPU 的使用率。
-
-
提高吞吐量:
-
减少了数据传输的延迟,提高了系统的吞吐量。
-
-
减少内存使用:
-
减少了不必要的内存分配和释放,提高了内存的使用效率。
-
3.零拷贝机制的实现方式
1. 使用 mmap
和 sendfile
mmap
和 sendfile
是 Linux 提供的两种零拷贝机制,它们可以显著减少数据在内存中的拷贝次数。
-
mmap
:-
mmap
将文件映射到用户空间的内存中,允许直接访问文件内容,而无需通过read
系统调用。 -
数据可以直接从用户空间的内存发送到网络,减少了内核空间和用户空间之间的拷贝。
-
-
sendfile
:-
sendfile
是一个系统调用,允许直接从一个文件描述符(通常是文件)发送数据到另一个文件描述符(通常是套接字)。 -
数据直接从内核缓冲区发送到网络,无需经过用户空间,减少了数据拷贝。
-
2. 使用 splice
splice
是另一种零拷贝机制,允许在两个文件描述符之间直接传输数据,而无需经过用户空间。splice
可以用于管道(pipe)和套接字之间的数据传输。
3. 使用 writev
和 readv
writev
和 readv
是 Linux 提供的 I/O 系统调用,允许将多个缓冲区的数据一次性写入或读取,减少了系统调用的次数。
-
writev
:-
允许将多个缓冲区的数据一次性写入文件描述符。
-
数据在内核空间中直接拼接,减少了用户空间和内核空间之间的拷贝。
-
-
readv
:-
允许从文件描述符一次性读取数据到多个缓冲区。
-
数据在内核空间中直接拆分,减少了用户空间和内核空间之间的拷贝。
-
4.muduo
中的零拷贝机制
muduo
网络库通过以下方式实现了零拷贝机制:
-
使用
writev
和readv
:-
muduo
的Buffer
类在读取和写入数据时,使用readv
和writev
系统调用,减少了数据在内核空间和用户空间之间的拷贝。
-
-
支持 预留空间,减少内存分配次数。
1. 预留空间(Prepend Space)
muduo::Buffer
类在设计上预留了一段空间(kCheapPrepend
),通常为 8 字节。这段预留空间位于缓冲区的开头,用于优化小数据写入操作。
-
优化小数据写入:当需要写入少量数据时,可以直接利用预留空间,避免了内存移动操作。
-
减少内存分配次数:通过预留空间,可以在不频繁扩容的情况下,高效地处理小数据的写入。
2. 动态扩容策略
muduo::Buffer
类支持动态扩容,当可写空间不足时,会根据当前数据量的大小动态调整缓冲区的大小。这种策略考虑了整个缓冲区的使用情况,包括预留空间和已读数据区域,从而避免了不必要的内存分配。
-
扩容条件:当可写空间不足时,
Buffer
会根据当前数据量的大小动态调整缓冲区的大小。 -
扩容策略:扩容时,
Buffer
会考虑预留空间和已读数据区域,从而避免了不必要的内存分配。
3. 内存分配优化
通过预留空间和动态扩容策略,muduo::Buffer
类显著减少了内存分配次数,从而提高了性能。
-
减少内存分配次数:通过预留空间和动态扩容策略,减少了不必要的内存分配。
-
提高性能:减少了内存分配次数,从而提高了数据读写的性能。
6.支持 TCP 服务器 & 客户端
-
封装了
TcpServer
和TcpClient
,简化开发,降低网络编程的复杂度。
7.集成日志系统
-
提供高效的日志模块
muduo::Logger
,支持日志等级、文件输出等。
muduo
网络库提供了一个高效且功能丰富的日志模块 muduo::Logger
,支持日志等级、文件输出、异步日志记录等功能。以下是其主要特点和使用方法:
1. 日志等级
muduo::Logger
提供了多种日志级别,包括 TRACE
、DEBUG
、INFO
、WARN
、ERROR
和 FATAL
。这些级别允许开发者根据日志的重要性进行筛选,从而在不同环境下控制日志输出的详细程度。
2. 异步日志记录
muduo
的日志系统采用异步日志记录机制,通过 AsyncLogging
类实现。这种方式可以有效防止日志输出阻塞程序的正常运行。AsyncLogging
使用独立的线程进行日志写入,主线程只需将日志消息放入队列,由后台线程负责写入磁盘。
3. 文件输出与滚动策略
muduo
支持将日志输出到文件,并提供了日志文件滚动功能。这包括基于文件大小和时间的滚动策略:
-
基于大小的滚动:当日志文件达到指定大小时,会自动创建新的日志文件。
-
基于时间的滚动:支持按天滚动日志文件,每天生成一个新的日志文件。
4. 日志格式与自定义输出
muduo::Logger
支持自定义日志格式,开发者可以根据需要配置日志的输出格式。此外,还可以通过设置输出函数,将日志输出到控制台、文件或其他目标。
2.Muduo 的 one loop per thread
-
Main Reactor(主Reactor) 只负责接收新连接,不处理数据读写。
-
Sub Reactors(子Reactor 线程池) 处理已建立连接的读写、回调、计算等任务。
-
每个线程一个 EventLoop(one loop per thread),保证 Reactor 线程间互不干扰。
1. 什么是 poll 的大小?
这里的 poll 指的是 epoll
的监听对象数,即每个 EventLoop 线程最多能管理的连接数。
-
poll
(或epoll_wait
)用来监听 socket 事件,比如可读、可写、新连接等。 -
每个 Reactor(线程)都有一个
epoll
实例,监听其负责的所有连接。 -
“大小固定” 指的是:在
one loop per thread
设计下,每个线程的epoll
管理的连接数受限于 CPU 资源。
2. 为什么要根据 CPU 数目确定?
Muduo 采用 多线程 + 负载均衡 来充分利用 CPU 资源:
-
一台服务器的 CPU 核心数 = 最佳 Sub Reactor 线程数。
-
每个 CPU 核心运行一个 Sub Reactor 线程,即每个 CPU 只运行一个
epoll
,避免线程间竞争,提高性能。
这样做的好处是:
-
最大化 CPU 利用率:每个 CPU 只运行一个 Reactor 线程,避免线程争用 CPU 资源。
-
减少锁竞争:每个
EventLoop
线程独立运行,不需要锁来同步访问共享资源。 -
负载均衡:新的连接采用 Round-Robin(轮询)方式分配给 Reactor 线程,均匀分布负载。
如果服务器有 4 核 CPU,Muduo 的线程模型如下:
1 个主 Reactor 线程(MainReactor
)—— 负责 accept()
接收新连接,并分发给 Sub Reactor 线程。
4 个子 Reactor 线程(SubReactors
)—— 处理 I/O 事件(read/write
)。
业务线程池(可选)—— 处理耗时任务,如数据库操作、计算等(避免阻塞 Sub Reactor 线程)
3.Moduo使用
1.小规模服务:单线程 Reactor,所有 I/O 和计算在一个线程内完成。
#include <functional> // 包含 std::bind 和 std::placeholders 等功能
#include <iostream> // 包含标准输入输出流
#include <muduo/base/Logging.h> // 包含 Muduo 的日志模块
#include <muduo/net/EventLoop.h> // 包含事件循环类
#include <muduo/net/TcpServer.h> // 包含 TCP 服务器类
#include <string> // 包含标准字符串类namespace muduo {
namespace net {// 定义一个 EchoServer 类,用于创建回声服务器
class EchoServer {
public:// 构造函数,初始化服务器EchoServer(muduo::net::EventLoop *loop, // 事件循环对象const muduo::net::InetAddress &addr, // 服务器地址和端口const std::string &name) // 服务器名称: server_(loop, addr, name), // 初始化 TcpServer 对象loop_(loop) // 保存事件循环对象的指针{// 注册连接回调函数// 当有新的客户端连接或断开连接时,调用 EchoServer::OnConnect 函数server_.setConnectionCallback(std::bind(&EchoServer::OnConnect, this, std::placeholders::_1));// 注册消息回调函数// 当接收到客户端发送的消息时,调用 EchoServer::OnMessage 函数server_.setMessageCallback(std::bind(&EchoServer::OnMessage, this, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3));}// 启动服务器void start() {server_.start(); // 调用 TcpServer 的 start 方法启动服务器}private:// 消息回调函数void OnMessage(const muduo::net::TcpConnectionPtr &conn, // 客户端连接对象muduo::net::Buffer *buff, // 消息缓冲区muduo::Timestamp time) // 消息到达的时间{std::string str = buff->retrieveAllAsString(); // 从缓冲区中读取消息conn->send(str); // 将消息原样返回给客户端conn->shutdown(); // 关闭连接的写端,表示不再发送数据}// 连接回调函数void OnConnect(const muduo::net::TcpConnectionPtr &conn) {if (conn->connected()) {// 如果客户端连接成功,打印客户端和服务器的地址信息std::cout << conn->peerAddress().toIpPort() // 客户端地址和端口<< " -> " << conn->localAddress().toIpPort() // 服务器地址和端口<< " state: online" << std::endl;} else {// 如果客户端断开连接,打印相关信息std::cout << conn->peerAddress().toIpPort() // 客户端地址和端口<< " -> " << conn->localAddress().toIpPort() // 服务器地址和端口<< " state: offline" << std::endl;conn->shutdown(); // 关闭连接}}muduo::net::EventLoop *loop_; // 事件循环对象指针muduo::net::TcpServer server_; // TCP 服务器对象
};} // namespace net
} // namespace muduoint main() {muduo::net::EventLoop loop; // 创建事件循环对象muduo::net::InetAddress addr("127.0.0.1", 8080); // 定义服务器地址和端口muduo::net::EchoServer server(&loop, addr,"EchoServer"); // 创建 EchoServer 对象server.start(); // 启动服务器,监听新连接,并注册事件回调loop.loop(); // 进入 Reactor 事件循环,不断监听和处理事件return 0;
}
std::bind创建一个“绑定器”,将一个函数(或成员函数)和它的参数绑定在一起,形成一个新的可调用对象
#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/Buffer.h>
#include <iostream>
#include <string>using namespace muduo;
using namespace muduo::net;class EchoClient {
public:EchoClient(EventLoop* loop, const InetAddress& serverAddr): loop_(loop),client_(loop, serverAddr, "EchoClient"),connectionEstablished_(false) {// 设置连接回调函数client_.setConnectionCallback(std::bind(&EchoClient::onConnection, this, std::placeholders::_1));// 设置消息回调函数client_.setMessageCallback(std::bind(&EchoClient::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));}void connect() {client_.connect();}void send(const std::string& message) {if (connectionEstablished_) {conn_->send(message);} else {std::cerr << "Connection not established yet." << std::endl;}}private:void onConnection(const TcpConnectionPtr& conn) {conn_ = conn;if (conn->connected()) {connectionEstablished_ = true;std::cout << "Connected to server." << std::endl;} else {connectionEstablished_ = false;std::cout << "Disconnected from server." << std::endl;}}void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) {std::string message = buf->retrieveAllAsString();std::cout << "Received message from server: " << message << std::endl;}EventLoop* loop_;TcpClient client_;TcpConnectionPtr conn_;bool connectionEstablished_;
};int main() {EventLoop loop;InetAddress serverAddr("127.0.0.1", 8080); // 服务器地址和端口EchoClient client(&loop, serverAddr);client.connect(); // 连接到服务器// 发送一条消息到服务器client.send("Hello, server!");loop.loop(); // 开始事件循环,让客户端开始运行return 0;
}
2.大规模服务:多线程 Reactor,主线程负责 I/O,工作线程池处理业务逻辑
#include <iostream>
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpServer.h>
#include <string>using namespace muduo;
using namespace muduo::net;class EchoServer {
public:EchoServer(EventLoop *loop, const InetAddress &listenAddr, int numThreads): server_(loop, listenAddr, "EchoServer") {// 设置线程池的线程数量server_.setThreadNum(numThreads);// 设置连接回调函数server_.setConnectionCallback(std::bind(&EchoServer::onConnection, this, std::placeholders::_1));// 设置消息回调函数server_.setMessageCallback(std::bind(&EchoServer::onMessage, this, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3));}void start() { server_.start(); }private:void onConnection(const TcpConnectionPtr &conn) {if (conn->connected()) {LOG_INFO << "Connection UP: " << conn->peerAddress().toIpPort();} else {LOG_INFO << "Connection DOWN: " << conn->peerAddress().toIpPort();}}void onMessage(const TcpConnectionPtr &conn, Buffer *buf,Timestamp receiveTime) {std::string msg(buf->retrieveAllAsString());LOG_INFO << "Received message from " << conn->peerAddress().toIpPort()<< ": " << msg;conn->send(msg); // 回声}TcpServer server_;
};int main(int argc, char *argv[]) {LOG_INFO << "pid = " << getpid();if (argc > 1) {EventLoop loop;InetAddress listenAddr(8080);int numThreads = argc > 2 ? atoi(argv[2]) : 3; // 默认使用 3 个线程EchoServer server(&loop, listenAddr, numThreads);server.start();loop.loop();} else {std::cerr << "Usage: " << argv[0] << " <port> [num_threads]" << std::endl;}return 0;
}
3.日志
Muduo 日志模块支持多种日志级别,每种级别用于记录不同严重程度的信息。以下是 Muduo 日志模块支持的日志级别及其用途:
1. TRACE
-
用途:记录最详细的信息,通常用于开发和调试阶段。
-
LOG_TRACE << "This is a trace message.";
2. DEBUG
-
用途:记录调试信息,用于开发和调试阶段。
-
LOG_DEBUG << "This is a debug message.";
3. INFO
-
用途:记录正常运行时的重要信息。
-
LOG_INFO << "This is an info message.";
4. WARN
-
用途:记录警告信息,表示程序可能存在问题,但不会影响正常运行。
-
LOG_WARN << "This is a warning message.";
5. ERROR
-
用途:记录错误信息,表示程序运行中出现了严重问题。
-
LOG_ERROR << "This is an error message.";
6. FATAL
-
用途:记录致命错误,通常会导致程序崩溃。
-
LOG_FATAL << "This is a fatal error message.";
日志级别从低到高依次为:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
配置日志级别
你可以通过配置文件或环境变量来设置日志的最低输出级别。例如,如果你只想输出 INFO
及以上级别的日志,可以设置日志级别为 INFO
。
3.CMake
add_executable(server server.cpp)# 链接Muduo库
target_link_libraries(server "/usr/local/lib/libmuduo_net.a" "/usr/local/lib/libmuduo_base.a"
)
相关文章:
Muduo网络库介绍
1.Reactor介绍 1.回调函数 **回调(Callback)**是一种编程技术,允许将一个函数作为参数传递给另一个函数,并在适当的时候调用该函数 1.工作原理 定义回调函数 注册回调函数 触发回调 2.优点 异步编程 回调函数允许在事件发生时…...
Cribl 导入文件来检查pipeline 的设定规则(eval 等)
Cribl 导入文件来检查pipeline 的设定规则(eval 等) 从这个页面先下载,或者copy 内容来创建pipeline: Reducing Windows XML Events | Cribl Docs...
2360. 图中的最长环
2360. 图中的最长环 题目链接:2360. 图中的最长环 代码如下: //参考链接:https://leetcode.cn/problems/longest-cycle-in-a-graph/solutions/1710828/nei-xiang-ji-huan-shu-zhao-huan-li-yong-pmqmr class Solution { public:int longest…...
深度学习入门(三):神经网络的学习
文章目录 前言人类思考 VS 机器学习 VS 深度学习基础术语损失函数常用的损失函数均方误差MSE(Mean Square Error)交叉熵误差(Cross Entropy Error)mini-batch学习 为何要设定损失函数数值微分神经网络学习算法的实现两层神经网络的…...
Python 推导式:简洁高效的数据生成方式
为什么需要推导式? 在Python编程中,我们经常需要对数据进行各种转换和过滤操作。传统的方法是使用循环结构,但这往往会导致代码冗长且不够直观。Python推导式(Comprehensions)应运而生,它提供了一种简洁、…...
HTML5+CSS3+JS小实例:带滑动指示器的导航图标
实例:带滑动指示器的导航图标 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, ini…...
一周学会Pandas2 Python数据处理与分析-Jupyter Notebook安装
锋哥原创的Pandas2 Python数据处理与分析 视频教程: 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Jupyter (Project Jupyter | Home)项目是一个非营利性开源项目,于2014年由IPython项目中诞生…...
FPGA状态机思想实现流水灯及HDLBits学习
目录 第一章 在DE2-115上用状态机思想实现LED流水灯1.1 状态机设计思路1.2 Verilog代码实现1.3. 仿真测试代码1.4 编译代码与仿真 第二章 CPLD和FPGA芯片的主要技术区别是什么?它们各适用于什么场合?2.1 主要技术区别2.2 适用场合 第三章 HDLBits学习3.1…...
【教程】Windows下 Xshell 连接跳板机和开发机
需求 使用远程连接工具 Xshell 连接跳板机,再从跳板机连接开发机,用户登陆方式为使用密钥。 方法 首先,建立一个会话,用于配置跳板机信息和开发机转跳信息: 在【连接】页面,给跳板机取个名字,…...
Java导出excel,表格插入pdf附件,以及实现过程中遇见的坑
1.不能使用XSSFWorkbook,必须使用HSSFWorkbook,否则导出excel后,不显示插入的图标和内容,如果是读取的已有的excel模板,必须保证excel的格式是xls,如果把xlsx通过重命名的方式改为xls,是不生效的,后面执行下…...
神马系统8.5搭建过程,附源码数据库
项目介绍 神马系统是多年来流行的一款电视端应用,历经多年的发展,在稳定性和易用性方面都比较友好。 十多年前当家里的第一台智能电视买回家,就泡在某论坛,找了很多APP安装在电视上,其中这个神马系统就是用得很久的一…...
cesium 材质 与 交互 以及 性能相关介绍
文章目录 cesium 材质 与 交互 以及 性能相关介绍1. Cesium 材质与着色器简介2. 具体实例应用核心代码及解释3. 代码解释 Cesium 交互1. 常见交互和事件类型2. 示例代码及解释3. 代码解释 cesium 性能优化数据加载与管理渲染优化相机与场景管理代码优化服务器端优化 案例分享1.…...
指令补充+样式绑定+计算属性+监听器
一、指令补充 1. 指令修饰符 1. 作用: 借助指令修饰符, 可以让指令更加强大 2. 分类: 1> 按键修饰符: 用来检测用户的按键, 配合键盘事件使用. keydown 和 keyup 语法: keydown.enter/v-on:keydown.enter 表示当enter按下的时候触发 keyup.enter/v-on:keyup.enter 表示当…...
基于Android的病虫害防治技术系统(源码+lw+部署文档+讲解),源码可白嫖!
摘要 基于Android的病虫害防治技术系统设计的目的是为用户提供一个病虫害防治技术管理的平台。与PC端应用程序相比,病虫害防治技术管理的设计主要面向于广大用户,旨在为用户提供一个查看科普内容,进行病虫识别、发帖交流的平台。 基于Androi…...
ffmpeg 使用不同编码器编码hevc的速度
1.核显uhd630 编码器hevc_qsv ffmpeg版本2024-03-14 2.73X 转码完成后大小 971mb 2.1680V4 编码器 libx265 ffmpeg版本2025-05-07 1.42x 转码完成后大小 176mb 3.RX588 编码器hevc_amf ffmpeg版本2024-03-14 转码完成后大小 376MB 4.1680v4dg1rx584 编码器hevc_amf ffm…...
【硬件模块】数码管模块
一位数码管 共阳极数码管:8个LED共用一个阳极 数字编码00xC010xF920xA430xB040x9950x9260x8270xF880x8090x90A0x88B0x83C0xC6D0xA1E0x86F0x8E 共阴极数码管:8个LED共用一个阴极 数字编码00x3F10x0620x5B30x4F40x6650x6D60x7D70x0780x7F90x6FA0x77B0x7…...
NO.64十六届蓝桥杯备战|基础算法-简单贪心|货仓选址|最大子段和|纪念品分组|排座椅|矩阵消除(C++)
贪⼼算法是两极分化很严重的算法。简单的问题会让你觉得理所应当,难⼀点的问题会让你怀疑⼈⽣ 什么是贪⼼算法? 贪⼼算法,或者说是贪⼼策略:企图⽤局部最优找出全局最优。 把解决问题的过程分成若⼲步;解决每⼀步时…...
ubuntu22.04LTS设置中文输入法
打开搜狗网址直接下载软件,软件下载完成后,会弹出安装教程说明书。 网址:搜狗输入法linux-首页搜狗输入法for linux—支持全拼、简拼、模糊音、云输入、皮肤、中英混输https://shurufa.sogou.com/linux...
基于YOLOv8的热力图生成与可视化-支持自定义模型与置信度阈值的多维度分析
目标检测是计算机视觉领域的重要研究方向,而YOLO(You Only Look Once)系列算法因其高效性和准确性成为该领域的代表性方法。YOLOv8作为YOLO系列的最新版本,在目标检测任务中表现出色。然而,传统的目标检测结果通常以边…...
常见设计系统清单
机构设计系统toB/toC网站GoogleMaterial DesignCm3.material.ioIBM CarbonDesign SystemBcarbondesignsystem.comSalesforceLightning Design SystemBlightningdesignsystem.comMicrosoftFluent Design SystemCfluent2.microsoft.design阿里Ant DesignCant.designSAPFiori Desi…...
React编程高级主题:错误处理(Error Handling)
文章目录 **5.2 错误处理(Error Handling)概述****5.2.1 onErrorReturn / onErrorResume(错误回退)****1. onErrorReturn:提供默认值****2. onErrorResume:切换备用数据流** **5.2.2 retry / retryWhen&…...
【设计模式】代理模式
简介 假设你在网上购物时,快递员无法直接将包裹送到你手中(比如你不在家)。 代理模式的解决方案是: 快递员将包裹交给小区代收点(代理),代收点代替你控制和管理包裹的访问。 代收点可以添加额外…...
局域网:电脑或移动设备作为主机实现局域网访问
电脑作为主机 1. 启用电脑的网络发现、SMB功能 2. 将访问设备开启WIFI或热点,用此电脑连接;或多台设备连接到同一WIFI 3. 此电脑打开命令行窗口,查看电脑本地的IP地址 Win系统:输入"ipconfig",回车后如图 4.…...
图论的基础
E - Replace(判环,破环成链) #include <bits/stdc.h> #include <atcoder/dsu>using namespace std; using namespace atcoder;const int C 26;int main() {int n;cin >> n;string s, t;cin >> s >> t;if (s …...
Jetpack Compose CompositionLocal 深入解析:局部参数透传实践
Jetpack Compose CompositionLocal 深入解析:局部参数透传实践 在 Jetpack Compose 中,如何优雅地在组件之间传递数据,而不需要层层传参? CompositionLocal 就是为了解决这个问题的! 1. 什么是 CompositionLocal&#…...
第十五届蓝桥杯大赛软件赛省赛Python 大学 C 组:3.数字诗意
题目1 数字诗意 在诗人的眼中,数字是生活的韵律,也是诗意的表达。 小蓝,当代顶级诗人与数学家,被赋予了”数学诗人”的美誉。他擅长将冰冷的数字与抽象的诗意相融合,并用优雅的文字将数学之美展现于纸上。 某日&…...
Oracle数据库数据编程SQL<8 文本编辑器Notepad++和UltraEdit(UE)对比>
首先,用户界面方面。Notepad是开源的,界面看起来比较简洁,可能更适合喜欢轻量级工具的用户。而UltraEdit作为商业软件,界面可能更现代化,功能布局更复杂一些。不过,UltraEdit支持更多的主题和自定义选项&am…...
P12013 [Ynoi April Fool‘s Round 2025] 牢夸 Solution
Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),有 m m m 个操作分两种: add ( l , r , k ) \operatorname{add}(l,r,k) add(l,r,k):对每个 i ∈ [ l , r ] i\in[l,r] i∈[l,r] 执行 …...
PostgreSQL LIKE 操作符详解
PostgreSQL LIKE 操作符详解 引言 在数据库查询中,LIKE 操作符是一种非常常用的字符串匹配工具。它可以帮助我们实现模糊查询,从而提高查询的灵活性。本文将详细介绍 PostgreSQL 中的 LIKE 操作符,包括其语法、使用方法以及一些注意事项。 LIKE 操作符语法 LIKE 操作符通…...
【前端】【Nuxt3】Nuxt3的生命周期
路由导航和中间件执行顺序 路由导航开始 中间件执行顺序: 全局中间件(middleware/*.global.js)布局中间件(在definePageMeta中定义的布局级中间件)页面中间件(在definePageMeta中定义的页面级中间件&#…...
热更新简介+xLua基础调用
什么是冷更新 开发者将测试好的代码,发布到应用商店的审核平台,平台方会进行稳定性及性能测试。测试成功后,用户即可在AppStore看到应用的更新信息,用户点击应用更新后,需要先关闭应用,再进行更新。 什么是…...
大钲资本押注儒拉玛特全球业务,累计交付超2500条自动化生产线儒拉玛特有望重整雄风,我以为它破产倒闭了,担心很多非标兄弟们失业
1. 交易概况 时间与主体:大钲资本于2025年4月1日正式宣布完成对儒拉玛特自动化技术(苏州)有限公司及其全球子公司和关联企业的收购。交易通过大钲资本旗下美元基金设立的儒拉玛特(新加坡)公司作为控股主体进行,交易金额未披露。 收购范围:包括儒拉玛特亚太、欧洲、北美等…...
FPGA系统开发板调试过程不同芯片的移植步骤介绍
目录 1.我目前使用的开发板 2.不同开发板的移植 步骤一:芯片型号设置 步骤二:约束修改 步骤三、IP核更新 关于FPGA系统开发板调试过程中不同芯片的移植。我需要先理清楚FPGA开发中移植到不同芯片的一般流程。首先,移植通常涉及到更换FPG…...
算法设计与分析5(动态规划)
动态规划的基本思想 将一个问题划分为多个不独立的子问题,这些子问题在求解过程中可能会有些数据进行了重复计算。我们可以把计算过的数据保存起来,当下次遇到同样的数据计算时,就可以查表直接得到答案,而不是再次计算 动态规划…...
ModuleNotFoundError: No module named ‘matplotlib_inline‘
ModuleNotFoundError: No module named matplotlib_inline 1. ModuleNotFoundError: No module named matplotlib_inline2. matplotlib-inlineReferences 如果你在普通的 Python 脚本或命令行中运行代码,那么不需要 matplotlib_inline,因为普通的 Python…...
Mysql 中的 B+树 和 B 树在进行数据增删改查后的结构调整过程是怎样的?
B 树的增、删、改、查数据的调整过程 在 MySQL 中,B 树 是一种广泛用于存储引擎(如 InnoDB)中的索引结构。B 树的结构使得它非常适合于处理大量数据的插入、删除和查询等操作。B 树是一种自平衡的树数据结构,其中所有的值都存储在…...
在Rust生态中探索高性能HTTP服务器:Hyperlane初体验
在Rust生态中探索高性能HTTP服务器:Hyperlane初体验 最近在调研Rust的HTTP服务器方案时,发现了一个有趣的新项目——Hyperlane。这个轻量级库宣称在保持简洁API的同时,性能表现可圈可点。作为Rust生态的长期观察者,我决定深入体验…...
AI医疗诊疗系统设计方案
AI医疗诊疗系统设计方案 1. 项目概述 1.1 项目背景 随着人工智能技术的快速发展,将AI技术应用于医疗诊疗领域已成为提升医疗服务效率和质量的重要途径。本系统旨在通过AI技术辅助医生进行诊疗服务,提供智能化的医疗决策支持。 1.2 项目目标 提供全面…...
k8s的StorageClass存储类和pv、pvc、provisioner、物理存储的链路
k8s的StorageClass存储类和pv、pvc、provisioner、物理存储的链路 StorageClass能自动创建pv 在控制器中,直接声明storageClassName,不仅能自动创建pvc,也能自动创建pv stoageclass来自于provisioner,provisioner来自于pod&#x…...
【移动编程技术】作业1 中国现代信息科技发展史、Android 系统概述与程序结构 作业解析
单选题(共 20 题,每题 5 分,满分 100 分) (单选题) 1946 年第一台计算机问世,计算机的发展经历了 4 个时代,它们是()。 选项: A. 模拟计算机、数字计算机、混合计算机、智…...
SQL Server数据库异常-[SqlException (0x80131904): 执行超时已过期] 操作超时问题及数据库日志已满的解决方案
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,获得2024年博客之星荣誉证书,高级开发工程师,数学专业,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开发技术,…...
使用ollama部署本地大模型(没有GPU也可以),实现IDEA和VS Code的git commit自动生成
详情 问豆包,提示词如下:收集下ollama相关信息,包括但不限于:官网地址/GitHub地址/文档地址 官网地址 https://ollama.com/ GitHub 地址 https://github.com/ollama/ollama 文档地址 https://github.com/ollama/ollama/blo…...
线程同步与互斥(上)
上一篇:线程概念与控制https://blog.csdn.net/Small_entreprene/article/details/146704881?sharetypeblogdetail&sharerId146704881&sharereferPC&sharesourceSmall_entreprene&sharefrommp_from_link我们学习了线程的控制及其相关概念之后&#…...
ngx_test_full_name
定义在 src\core\ngx_file.c static ngx_int_t ngx_test_full_name(ngx_str_t *name) { #if (NGX_WIN32)u_char c0, c1;c0 name->data[0];if (name->len < 2) {if (c0 /) {return 2;}return NGX_DECLINED;}c1 name->data[1];if (c1 :) {c0 | 0x20;if ((c0 &…...
R 列表:深入解析及其在数据分析中的应用
R 列表:深入解析及其在数据分析中的应用 引言 在R语言中,列表(List)是一种非常重要的数据结构,它允许将不同类型的数据项组合在一起。列表在数据分析、统计建模以及数据可视化中扮演着关键角色。本文将深入探讨R列表…...
智能体中的知识库、数据库与大模型详解
前言 在 LLM(大语言模型)驱动的智能体架构中,知识库(Knowledge Base)、数据库(Database)和大模型(LLM)是关键组成部分,它们共同决定了智能体的理解能力、决策…...
AMD Versal™ AI Core Series VCK190 Evaluation Kit
AMD Versal™ AI Core Series VCK190 Evaluation Kit AMD VCK190 是首款 Versal™ AI Core 系列评估套件,可帮助设计人员使用 AI 和 DSP 引擎开发解决方案,与当前的服务器级 CPU 相比,该引擎能够提供超过 100 倍的计算性能。Versal AI Core …...
ARM-外部中断,ADC模数转换器
根据您提供的图片,我们可以看到一个S3C2440微控制器的中断处理流程图。这个流程图展示了从中断请求源到CPU的整个中断处理过程。以下是流程图中各个部分与您提供的寄存器之间的关系: 请求源(带sub寄存器): 这些是具体的…...
【从零实现Json-Rpc框架】- 项目实现 - 客户端注册主题整合 及 rpc流程示意
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
AWS 云运维管理指南
一、总体目标 高可用性:通过跨可用区 (AZ) 和跨区域 (Region) 的架构设计,确保系统运行可靠。性能优化:优化AWS资源使用,提升应用性能。安全合规:利用AWS内置安全服务,满足行业合规要求(如GDPR、ISO 27001、等保2.0)。成本管控:通过成本优化工具,减少浪费,实现FinOp…...