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

【C语言】epoll_wait / select

一、epoll_wait和select对比

1. 阻塞和非阻塞

在Linux C语言中进行socket编程时,`epoll_wait` 和 select 都是用于多路I/O复用的系统调用,但是它们的行为可以设置为阻塞和非阻塞模式,这取决于调用它们时所使用的参数。

让我们分别看看 epoll_wait 和 select

epoll_wait

   epoll_wait 函数用于等待由 epoll 文件描述符指向的事件,它可以工作在阻塞模式,也可以工作在非阻塞模式。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

   在这里,`timeout` 参数决定 epoll_wait 的行为,其值可以是:
   - -1 表示无限期阻塞,直到有事件发生。
   - 0 表示非阻塞调用,即使没有事件,也立即返回。

   - 大于0的值表示等待指定毫秒数,如果在这个时间段内没有事件发生,它将返回。

select

   select 函数也是多路I/O复用的调用,它监视一组文件描述符,以查看是否有数据可读、可写或有异常。

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

   其中,`timeout` 参数同样控制 select 的行为,可以设置为:
   - NULL 表示无限期阻塞,直到有文件描述符就绪。
   - 其中的 tv_sec 和 tv_usec 成员均为 0 表示非阻塞调用,立即返回。

   - 时间结构设置为某个特定的时间量(秒和微秒),这意味着 select 会阻塞但最多等待这段时间。

`epoll_wait` 和 select 都可以根据需求设置为阻塞或非阻塞。在性能方面,`select` 受制于能够监视的文件描述符数量的限制(通常是FD_SETSIZE,通常为1024),而 epoll 更适合大规模文件描述符的监视,因为 epoll 内部使用了不同的机制,它不受固定大小限制,并且当活动文件描述符的数量远小于总数时,它能提供更好的性能。

选择使用 select 或 epoll(以及 poll),取决于具体的应用需求以及对性能和可扩展性的考量。在现代Linux系统上,`epoll` 通常是大规模且长时间运行的网络服务程序的首选。

2. 工作方式

在Linux C语言socket编程中,`epoll_wait`和`select`都是用来监视多个文件描述符的可读、可写、异常等状态的系统调用,但它们的工作方式有所不同。

select

select函数是POSIX标准的一部分,它允许应用程序监视一组文件描述符,等待一个或多个文件描述符成为非阻塞状态。`select`使用一个固定大小的文件描述符集合,并且在每次调用`select`时,都需要重新设置文件描述符集和超时时间。这种方法在监控大量文件描述符时效率不高,因为它需要线性地检查每一个文件描述符。

epoll

epoll系列函数是Linux特有的,提供了一种更高效的机制来处理大量文件描述符。`epoll`使用一个事件表来跟踪每个文件描述符的状态,并在文件描述符状态改变时通知应用程序。`epoll`的优势在于它不需要在每次调用时都重新设置文件描述符集合,而且它能以常数时间复杂度管理文件描述符集合,这在处理大量文件描述符时可以提供更好的性能。

当使用`epoll`时,通常是通过以下步骤操作的:

1. 使用`epoll_create`创建一个`epoll`实例。
2. 使用`epoll_ctl`添加、修改或删除要监视的文件描述符。

3. 使用`epoll_wait`等待事件的发生,并处理发生的事件。

如果选择使用`epoll`系列函数来进行socket编程,就不需要使用`select`函数了,因为`epoll`提供了更高效且功能更完备的替代方案。在处理大规模并发连接时,`epoll`通常是更好的选择。

二、epoll代码示例

1. python示例

epoll 是 Linux 上的一个高效的 IO 事件通知系统,它能够告诉你哪些文件描述符(sockets、文件、pipes等)已经准备好执行非阻塞的读取或写入操作。与传统的 select 和 poll 相比,`epoll` 在处理大量文件描述符时更加高效。下面是一个简单的 epoll 示例代码。

注意:以下示例代码仅适用于 Linux 系统。

import socket
import select
import errno# 创建一个 TCP/IP 套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置套接字选项,允许我们重新绑定同一个端口
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 绑定套接字到端口
server_address = ('localhost', 10000)
print('开始在 %s 端口 %s 上监听' % server_address)
server_socket.bind(server_address)# 监听入站连接
server_socket.listen(1)# 设置非阻塞模式
server_socket.setblocking(0)# 创建一个 epoll 对象
epoll = select.epoll()# 在 epoll 事件循环中注册服务器套接字,监听读事件
EPOLLIN = select.EPOLLIN
epoll.register(server_socket.fileno(), EPOLLIN)try:connections = {}requests = {}responses = {}while True:# 等待事件发生,可能会使得程序进入阻塞状态events = epoll.poll(1)for fileno, event in events:if fileno == server_socket.fileno():# 新入站连接connection, client_address = server_socket.accept()print('新连接来自', client_address)connection.setblocking(0)# 注册读事件epoll.register(connection.fileno(), EPOLLIN)connections[connection.fileno()] = connectionrequests[connection.fileno()] = b''responses[connection.fileno()] = b''elif event & EPOLLIN:# 可读事件data = connections[fileno].recv(1024)if data:print(f"接收到 {len(data)} 字节: '{data.decode()}'")requests[fileno] += dataelse:# 如果没有数据,意味着客户端关闭了连接epoll.unregister(fileno)connections[fileno].close()del connections[fileno], requests[fileno], responses[fileno]elif event & select.EPOLLOUT:# TODO: 可写事件处理逻辑# 在这里处理 responses 字典中待发送的数据passelif event & select.EPOLLHUP:# TODO: 处理挂起的连接epoll.unregister(fileno)connections[fileno].close()del connections[fileno]
finally:# 释放资源epoll.unregister(server_socket.fileno())epoll.close()server_socket.close()

这段代码创建了一个 TCP 服务器,它使用 epoll 来管理每个连接的事件。在这个简单的例子中,服务器仅仅是读取客户端数据,并打印出来。

注意代码中有几个 TODO 注释,提示在哪里添加处理可写事件和挂起连接的代码。对于一个完整的服务器,通常还需要处理客户端发送的请求,并产生响应发送回客户端。

确保在实际运行这段代码前,已经对 epoll、非阻塞套接字和事件驱动编程有所理解。通过细读并且动手实践,将能够理解在一个高性能网络程序中如何使用 epoll

2. C语言示例

Linux C 语言中使用 epoll 的 socket 编程示例相对复杂,因为它涉及对 socket API 的理解以及对事件驱动编程模型的使用。以下是一个简单的 epoll 示例,这个示例程序的目的是创建一个 TCP echo 服务器,它使用 epoll 来处理多个客户端连接。

请注意,以下代码将仅作为示教用途,它并没有处理所有可能的错误,并且不应该在生产环境中直接使用。此外,确保在编译时链接到 -lnsl 库(如果需要)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <sys/epoll.h>#define PORT        12345
#define MAX_EVENTS  32void die(const char *msg) {perror(msg);exit(EXIT_FAILURE);
}int main() {int listenfd, connfd, epollfd, nfds, i;struct sockaddr_in addr;struct epoll_event ev, events[MAX_EVENTS];// 创建和绑定 socketlistenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0) die("socket() failed");bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = INADDR_ANY;if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)die("bind() failed");// 监听 socketif (listen(listenfd, 10) != 0)die("listen() failed");// 创建 epoll 实例epollfd = epoll_create1(0);if (epollfd < 0) die("epoll_create1() failed");ev.events = EPOLLIN;ev.data.fd = listenfd;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) == -1)die("epoll_ctl: listenfd");for (;;) {nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);if (nfds < 0) die("epoll_wait() failed");for (i = 0; i < nfds; ++i) {if (events[i].data.fd == listenfd) {connfd = accept(listenfd, NULL, NULL);if (connfd < 0) die("accept() failed");ev.events = EPOLLIN | EPOLLET;ev.data.fd = connfd;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1)die("epoll_ctl: connfd");} else {char buffer[256];ssize_t bytes_read;// 处理客户端数据bytes_read = read(events[i].data.fd, buffer, sizeof(buffer));if (bytes_read <= 0) {// 读取完成或者发生错误,关闭连接close(events[i].data.fd);} else {buffer[bytes_read] = '\0';printf("Received: %s", buffer);// Echo 回数据write(events[i].data.fd, buffer, bytes_read);}}}}close(listenfd);return 0;
}

在这个示例中,我们创建了一个 TCP 服务器 socket,并将它绑定到指定的端口(这里是 12345)。我们对这个 socket 调用了 listen,把它变成一个监听 socket,并创建了一个 epoll 实例来处理链接事件和数据接收事件。服务器以事件循环的方式运行,使用 epoll 等待新事件。

当新的连接到达时,它会被接受并添加到 epoll 实例以供监视。当已连接的 socket 有数据可读时,服务器会读取这些数据并简单地将其作为 echo 响应发回客户端。

记得在多客户端的情况下还应该考虑:

- 不同客户端之间进行全面的状态管理。
- 对于边缘触发(EPOLLET)的处理更为复杂,需要确保数据完全读取。
- 此代码示例没有使用SSL,对于安全连接需要集成SSL库。

- 更强的错误处理和程序稳健性措施。

三、epoll事件

epoll 是 Linux 下的一种 I/O 事件通知机制,它可以高效地处理数以万计的文件描述符。当注册一个文件描述符(比如 socket)到 epoll 实例时,需要指定感兴趣的事件类型。`epoll` 能够监视多种类型的事件,以下是一些常见的 epoll 事件及其含义:
1. EPOLLIN:表示对应的文件描述符可以读取(非高优先级)数据,比如 TCP Socket 的接收缓冲区非空,可以调用 recv(),或者 UDP Socket 收到了数据包,可以调用 recvfrom()。
2. EPOLLOUT:表示对应的文件描述符可以写入数据,比如 TCP Socket 的发送缓冲区有空间,可以调用 send()。
3. EPOLLPRI:表示对应的文件描述符有紧急的数据可读(带外数据),这适用于 TCP Socket。
4. EPOLLERR:表示对应的文件描述符发生了错误。这不必由用户设置,即使未指定,系统也会报告它。
5. EPOLLHUP:表示对应的文件描述符被挂断。如果 Socket 对端关闭了连接,或者是某种半关闭状态,你会收到这个事件。类似 EPOLLERR,这个事件也会不论是否被用户请求都报告它。
6. EPOLLRDHUP(自 Linux 2.6.17 版本起):表示 Socket 监测到连接的另一端关闭了连接或者半关闭了连接。适用于 TCP Socket。
7. EPOLLET:将 epoll 设置为边缘触发(Edge Triggered)模式,这意味着 epoll 仅通知你一次事件,直到下一个事件发生,不会再次通知你相同的事件。
8. EPOLLONESHOT:表示一次性的事件,当事件被触发后,如果需要再次被触发必须重新设置。
这些事件均适用于 TCP 和 UDP Socket,但是某些事件在实际应用中更常用于 TCP(如:`EPOLLRDHUP`、`EPOLLPRI`)。由于 TCP 是一个面向连接的协议,它支持如连接的建立、数据的可靠传输、流控制等多种事件;而 UDP 是一个无连接的协议,通常只关心数据的接收与发送(`EPOLLIN` 和 EPOLLOUT)。在使用 UDP 时,`EPOLLERR` 也可能被用来处理错误情况。

四、处理EPOLLERR事件

在Linux系统中,`epoll` 是一种高效的 IO 事件通知机制,它能够告诉你哪些文件描述符(file descriptors, FDs)已经准备好进行非阻塞的读写操作。`EPOLLERR` 是 epoll 等待 (epoll_wait) 函数返回的可能事件之一,它表明一个出错的文件描述符。
当 epoll_wait 检测到某个文件描述符上有 EPOLLERR 事件时,通常需要采取以下步骤来处理它:
1. 识别错误原因:当 EPOLLERR 发生时,需要确定导致错误的具体原因。可以通过调用 getsockopt 函数与 SO_ERROR 选项来检索和清除该文件描述符的错误状态。

   int err;socklen_t errlen = sizeof(err);if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen) == 0) {// Now 'err' contains the error code or 0 if there's no error}

err 中可能包含的错误码是一系列定义在 <errno.h> 头文件中的标准 POSIX 错误码。这些错误码表示了套接字上可能发生的不同错误。以下是一些常见的错误码和它们的含义:
- ECONNRESET - 连接被对端重置。
- ETIMEDOUT - 连接尝试超时。
- ECONNREFUSED - 连接被远程主机拒绝。
- EHOSTDOWN - 主机已宕机。
- EHOSTUNREACH - 没有到主机的网络路由。
- EPIPE - 管道破裂,通常是在对一个非连接的套接字执行写操作时。
- ENETUNREACH - 网络不可达。
- ENETDOWN - 网络系统不可用。
- EAGAIN 或 EWOULDBLOCK - 资源临时不可用。
处理这些错误通常需要根据应用程序的上下文和设计来决定。以下是一些基本的处理策略:
- 重新连接:对于 ECONNRESET 或 ETIMEDOUT,可能需要尝试重新建立连接。
- 报告错误:对于 ECONNREFUSED、`EHOSTUNREACH` 或 ENETUNREACH,应当报告错误给用户并考虑是否需要重试。
- 资源管理:对于 EAGAIN 或 EWOULDBLOCK,这通常意味着非阻塞操作会在没有立即完成的情况下返回。可能需要稍后再试或者使用异步 I/O。
清除文件描述符的错误状态:
在调用 getsockopt 函数并使用 SO_ERROR 选项之后,错误状态就被清除了。如果检索到 err 变量中的错误码后,这个特定的套接字错误就被认为是 "已被消费" 的。以后再次调用带 SO_ERROR 选项的 getsockopt 将返回 0,除非自从上一次调用以来发生了新的错误。
注意,对文件描述符本身的错误状态执行 "清除" 操作只是指读取出错误信息。如果套接字真正遭受了致命错误(比如 ECONNRESET),为了恢复,将需要关闭它,并且取决于情况,或许需要创建一个新的套接字来替代。某些错误可能是暂时性的,可能可以继续使用现有的套接字,但通常还是需要应用程序采取一些形式的恢复措施。

2. 响应错误:错误的具体原因将决定你的下一步行动。有时,可能需要关闭并重新打开文件描述符;其他情况下,可能需要记录错误并通知应用程序其他部分。
3. 关闭文件描述符:如果文件描述符因错误不再可用,应该关闭它。继续使用一个出现错误的文件描述符可能导致未定义行为。

close(fd);

4. 清理资源:如果该文件描述符是某种资源的一部分(例如一个客户端连接),确保适当地清理资源,例如释放内存、取消定时器等。
5. 日志记录:记录日志信息可以帮助调试和跟踪系统的行为,尤其是错误条件发生时。
6. 用户通知(如有必要):如果错误会影响用户操作,你可能需要通知用户或启动一些恢复流程。
值得注意的是,`EPOLLERR` 通常与其他 I/O 事件(`EPOLLIN`、`EPOLLOUT` 等)一起返回,表示即使有错误,文件描述符也可能处于可读或可写状态。但是,处理读写之前应该始终先检查和响应错误。此外,对于某些类型的文件描述符(如 epoll 自己的文件描述符),`EPOLLERR` 也可能意味着某些系统层面的问题,你需要具备相应的处理逻辑。

五、EPOLLHUP和EPOLLRDHUP事件的区别

EPOLLHUP和`EPOLLRDHUP`是Linux提供的epoll机制中的两个事件,用于监控文件描述符的状态变化。这两个事件与网络编程中的socket状态变化有关,尤其是在处理TCP连接时。以下是它们的定义和区别:
EPOLLHUP(挂起事件):
- EPOLLHUP标志用于表示一个挂起的事件。这通常意味着文件描述符被挂断(无更多的读写操作能够执行),无论是另一端的正常关闭(如调用`close()`),还是因为某种错误而非正常关闭。
- EPOLLHUP事件表明连接已经完全关闭,或者对应的socket出现了一些异常,不再可用。
- 在某些情况下,即使没有向epoll注册`EPOLLHUP`事件,epoll_wait仍然可能返回该事件。这是因为`EPOLLHUP`被视为一个异常事件,epoll希望你能够注意到并采取适当的行动。
EPOLLRDHUP(读挂断事件):
- EPOLLRDHUP是在Linux内核2.6.17中引入的一个标志,用于表示对端的socket已经关闭了写操作,或者说执行了半关闭(关闭了连接的写入部分)。它通常用于检测TCP连接的这种"半关闭"状态。
- EPOLLRDHUP事件可以让程序更加精细地检测到对方是否还在发送数据,或者只是单方面关闭了发送通道。可以在检测到`EPOLLRDHUP`后继续从socket读取直到得到EOF,这时才真正意味着对方完成了所有发送。
- 如果希望通过epoll监测这个事件,需要显式地在注册epoll事件时指定`EPOLLRDHUP`。
区别:
- EPOLLHUP通常用来表示文件描述符完全不可用了(不再连接)。
- EPOLLRDHUP用来表示对端关闭了写半部分(半关闭状态),本端仍可以读取剩余数据。
实际用法中的注意:
- 在编写使用epoll机制的网络编程时,应当注意处理`EPOLLHUP`和`EPOLLRDHUP`事件。例如,一个web服务器需要知道什么时候客户端关闭了连接,这样才能使资源得到及时释放。
- EPOLLRDHUP在TCP连接管理中尤其有用,它允许服务端检测到客户端的半关闭状态,从而能够优雅地关闭连接。
- 当使用epoll时记得仔细区分并处理这两种事件,避免误解它们的意图而导致bug或资源泄漏。
总结来说,`EPOLLRDHUP`和`EPOLLHUP`都是与连接关闭有关的事件,但具体的语义和用途是有区别的。理解并正确处理这些事件对于开发稳定和高效的网络服务是非常关键的。

六、EPOLLPRI事件

在网络编程中,有两种数据传输方式:普通数据传输和带外数据传输。普通数据是应用程序正常通信的数据,它们遵循正常的数据流和处理顺序。而带外数据,也称作紧急数据,是一种特殊的传输方式,使得某些数据能够越过正常的数据流,得到网络栈以及应用程序的优先处理。
带外数据主要特征如下:
1. 优先级高:带外数据被设计为有更高的优先级,它会被发送和接收的过程中优先对待。
2. 数量少:相对于普通数据,带外数据通常不用于大量数据的传输,而是发送少量紧急信息。
3. 单独的通道:带外数据经常被看作是通过一个独立的通道进行传输,以便在接收端立刻被注意到并处理,它与普通数据流分开。
4. 紧急通知:带外数据通常用于告知远端系统某种紧急状况或者控制信息,如TCP协议中的紧急指针字段被用于通知接收端有紧急数据要处理。
在TCP/IP协议中,带外数据通常是通过TCP的URG(紧急)标志位来实现的。当一个TCP段设置了URG标志位时,紧跟在TCP头之后的数据被标记为紧急数据。收到这样的TCP段时,操作系统会通知应用程序有紧急数据到达。
在应用程序层面,带外数据通常通过特定的API调用来发送和接收。例如,在套接字编程中,可通过设置SO_OOBINLINE的套接字选项,决定是在正常数据流中接收带外数据,还是通过特定的带外数据机制处理它们。
带外数据的一个常见应用示例是中断远程服务器上长时间运行的进程。例如,用户可能发送一个紧急数据包来通知服务器立即停止当前的传输。
然而,需要注意的是,不是所有的协议或系统都支持带外数据。在实际应用中,带外数据由于其复杂性和一致性问题,并不经常使用,很多新的协议和应用都避免使用它。在设计现代网络应用时,更通常的做法是在应用层面设定协议来处理紧急情况,而不是依赖底层网络的带外数据功能。

七、epoll_create和epoll_create1有什么不同?

epoll_create 和 epoll_create1 都是用来创建一个新的 epoll 实例的系统调用,但它们之间有一些差异:
1. epoll_create:
   - 在较旧的 Linux 内核版本中引入。
   - 需要一个参数 size,该参数在早期用于告诉内核监听的文件描述符数量。然而,在现代 Linux 内核中,这个参数并不起作用,因为 epoll 会根据需要动态调整,但出于向后兼容性的原因,这个参数必须大于零。
   - 用法示例:`int epoll_fd = epoll_create(1);`
   - 不接受标志(flags)参数,所以创建的 epoll 文件描述符总是具有相同的属性。
2. epoll_create1:
   - 在较新的 Linux 内核版本(2.6.27 及之后版本)中引入。
   - 添加了一个参数 flags,它允许你改变 epoll 文件描述符的行为,例如设置为非阻塞。
   - flags 参数可以是以下之一:
      - 0:效果与 epoll_create 相同。
      - EPOLL_CLOEXEC:使用这个标志创建的 epoll 文件描述符,在执行 exec 系列调用产生的新进程中将会被自动关闭。这有助于防止文件描述符泄漏到子进程。
   - 如果不需要设置任何标志,可以传入 0 作为 flags 的值。
   - 用法示例:`int epoll_fd = epoll_create1(0); 或者 int epoll_fd = epoll_create1(EPOLL_CLOEXEC);`
总体来说,`epoll_create1` 提供了更多的控制和扩展性,并且是推荐使用的方式,如果你的环境中存在支持它的 Linux 内核版本。如果仅需要创建一个 epoll 实例而不考虑 exec 调用中的文件描述符行为,那么使用 0 作为 flags 的值就足够了。 

八、普通文件并不是epoll支持的文件描述符类型

错误 "epoll_ctl: Operation not permitted" 通常发生在尝试对不支持epoll操作的文件描述符执行epoll_ctl()时。Epoll 主要用于I/O多路复用,它适用于套接字、管道和其他一些特定类型的文件描述符,这些文件描述符应该是可边缘触发的(ET)或水平触发的(LT)。
普通文件,如尝试打开的 test.txt,并不是epoll支持的文件描述符类型。对于普通文件,因为它们总是准备好被读取或写入,所以epoll机制不适用。普通文件的I/O是非阻塞的,epoll等待机制仅适用于可能阻塞的操作,如套接字I/O。
如果目的是监视文件的变化,可以考虑使用 inotify 机制而不是 epoll。`inotify` 机制是用来监视文件系统事件的,比如文件的创建、修改、删除等。
然而,如果仍希望使用 epoll,需要使用它来监视套接字之类的文件描述符,而不是常规文件。对于常规文件I/O,可以直接使用 read()、`write()` 等系统调用,通常不需要使用 epoll 这样的机制。
如果需要使用epoll监控文件描述符,则可以测试套接字的场景。例如,可以创建一个简单的网络服务,使用套接字并使用epoll来处理来自客户端的连接和数据。 

相关文章:

【C语言】epoll_wait / select

一、epoll_wait和select对比 1. 阻塞和非阻塞 在Linux C语言中进行socket编程时&#xff0c;epoll_wait 和 select 都是用于多路I/O复用的系统调用&#xff0c;但是它们的行为可以设置为阻塞和非阻塞模式&#xff0c;这取决于调用它们时所使用的参数。 让我们分别看看 epoll…...

Java 数据抓取

大家好我是苏麟 , 今天聊聊数据抓取 . 大家合理使用 注意&#xff0c;爬虫技术不能滥用&#xff0c;干万不要给别人的系统造成压力、不要侵犯他人权益! 数据抓取 实质上就是java程序模拟浏览器进行目标网站的访问&#xff0c;无论是请求目标服务器的接口还是请求目标网页内容…...

深度学习之处理多维特征的输入

我们首先来看一个糖尿病的数据集&#xff1a; 在数据集中&#xff0c;我们称每一行叫做sample&#xff0c;表示一个样本&#xff0c;称每一列是feature&#xff0c;也就是特征在数据库里面这就是一个关系表&#xff0c;每一行叫做记录&#xff0c;每一列叫做字段。 每一个样本都…...

西瓜书读书笔记整理(十二) —— 第十二章 计算学习理论(下)

第十二章 计算学习理论&#xff08;下&#xff09; 12.4 VC 维&#xff08;Vapnik-Chervonenkis dimension&#xff09;12.4.1 什么是 VC 维12.4.2 增长函数&#xff08;growth function&#xff09;、对分&#xff08;dichotomy&#xff09;和打散&#xff08;shattering&…...

初探分布式链路追踪

本篇文章&#xff0c;主要介绍应用如何正确使用日志系统&#xff0c;帮助用户从依赖、输出、清理、问题排查、报警等各方面全面掌握。 可观测性 可观察性不单是一套理论框架&#xff0c;而且并不强制具体的技术规格。其核心在于鼓励团队内化可观察性的理念&#xff0c;并确保由…...

闭包的理解?闭包使用场景

说说你对闭包的理解&#xff1f;闭包使用场景 #一、是什么 一个函数和对其周围状态&#xff08;lexical environment&#xff0c;词法环境&#xff09;的引用捆绑在一起&#xff08;或者说函数被引用包围&#xff09;&#xff0c;这样的组合就是闭包&#xff08;closure&#…...

openssl3.2 - 帮助文档的整理

文章目录 openssl3.2 - 帮助文档的整理概述笔记整理后, 非空的文件夹如下整理后, 留下的有点用的文件列表如下备注END openssl3.2 - 帮助文档的整理 概述 openssl3.2源码工程编译安装完, 对于库的使用者, 有用的文档, 远不止安装的那些html. 用everything查找, 配合手工删除,…...

中移(苏州)软件技术有限公司面试问题与解答(5)—— Linux进程调度参数调优是如何通过代码实际完成的1

接前一篇文章&#xff1a;中移&#xff08;苏州&#xff09;软件技术有限公司面试问题与解答&#xff08;0&#xff09;—— 面试感悟与问题记录 本文对于中移&#xff08;苏州&#xff09;软件技术有限公司面试问题中的“&#xff08;11&#xff09;Linux进程调度参数调优是如…...

初识C语言·文件操作

目录 1 关于文件 i)文件的基本知识 ii)数据文件的分类 2 文件打开和关闭 i)流和标准流 ii)文件指针 iii)文件打开和关闭 3 文件的顺序读写 i) fgetc fputc ii) fgets fputs iii) fscanf fprintf iv) fwrite fread 4 对比一组函数 scanf/fscanf/sscanf/printf/fpri…...

跨境卖家:如何利用自养号测评抢占市场先机?

在当今的跨境电商领域&#xff0c;产品的销量和评价是影响产品在市场上的表现的关键因素。对于卖家而言&#xff0c;自行养号进行产品测评不仅有助于提升销量&#xff0c;更成为了他们在这个竞争激烈的市场中保持竞争力的必备策略。 相较于一些卖家仍然依赖于服务商进行测评&a…...

开发手札:Github Timeout 22

今天&#xff08;2024.01.26日&#xff09;&#xff0c;提交github又出现了ssh connect timeout errorcode 22&#xff0c;不论是创建新的sshkey还是配置.ssh/config都没用。 偶然在知乎上看到了解决方案&#xff0c;只需要在host中添加&#xff1a; 140.82.113.4 githu…...

学习鸿蒙基础(3)

1.组件重用样式 如果每个组件的样式都需要单独设置&#xff0c;在开发过程中会出现大量代码在进行重复样式设置&#xff0c;虽然可以复制粘贴&#xff0c;但为了代码简洁性和后续方便维护&#xff0c;可以采用公共样式进行复用的装饰器Styles。 Styles装饰器可以将多条样式设置…...

2024/1/27 备战蓝桥杯 1-2

目录 金币 0金币 - 蓝桥云课 (lanqiao.cn) 天干地支 0天干地支 - 蓝桥云课 (lanqiao.cn) 明明的随机数 0明明的随机数 - 蓝桥云课 (lanqiao.cn) 浇灌 0灌溉 - 蓝桥云课 (lanqiao.cn) 金币 0金币 - 蓝桥云课 (lanqiao.cn) 思路&#xff1a;放两种情况&#xff08;k:代…...

【PyQt】02-基本UI

文章目录 前言一、首先了解什么是GUI&#xff1f;二、初学程序1.界面展示代码运行结果 2.控件2.1按钮展示代码运行结果 2.2 纯文本和输入框代码运行结果 3、重新设置大小 -resize4、移动窗口-move()5、设置界面在电脑中央5.1 代码运行结果 6、设置窗口图标代码运行结果 7、布局…...

无需 Root 卸载手机预装软件,精简过的老年机又行了

基础准备 准备目标手机、USB 数据线、以及一台电脑。手机 USB 连接电脑&#xff0c;开发者选项中打开 USB 调试。&#xff08;开发者选项默认隐藏&#xff0c;需要在关于手机中多次点击版本号才能调出&#xff09;。 安装手机驱动&#xff0c;下载安装 ADB 工具包。 开始操作…...

【Spring连载】使用Spring Data访问Redis(一)----快速指南

【Spring连载】使用Spring Data访问Redis&#xff08;一&#xff09;----快速指南 一、导入依赖二、Hello World程序 一、导入依赖 在pom.xml文件加入如下依赖就可以下载到spring data redis的jar包了&#xff1a; <dependency><groupId>org.springframework.boot…...

Redis 学习笔记 2:Java 客户端

Redis 学习笔记 2&#xff1a;Java 客户端 常见的 Redis Java 客户端有三种&#xff1a; Jedis&#xff0c;优点是API 风格与 Redis 命令命名保持一致&#xff0c;容易上手&#xff0c;缺点是连接实例是线程不安全的&#xff0c;多线程场景需要用线程池来管理连接。Redisson&…...

React Native

学习目标 解决以下问题: 1.什么是 React Native &#xff1f;为什么它的名字中有 “Native” 字样&#xff1f; 2.为什么 React Native 如此之酷&#xff1f; 3.我们可以分别使用 React Native 和 React 来开发什么&#xff1f; 4.为什么会出现 ReactDOM &#xff1f;它是做什…...

分布式搜索引擎_学习笔记_3

分布式搜索引擎03 0.学习目标 1.数据聚合 **聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售…...

机器学习系列——(二)主要任务

导语&#xff1a; 随着信息时代的到来&#xff0c;机器学习作为一项重要技术正逐渐渗透到我们的生活和工作中。它的主要任务是通过使用数据和算法&#xff0c;让计算机系统从中学习并改进性能&#xff0c;使其能够更智能地处理问题和做出决策。本文将详细介绍机器学习的主要任…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...