redis高级篇之IO多路复用select方法简介 第174节答疑

1、bitmap最大1024位,一个进程最多只能处理1024个客户端
2、&rset不可重用,每次socket有数据就相应的位会被置位
3、文件描述符数组拷贝到了内核态(只不过无系统调用切换上下文的开销。(内核层可优化为异步事件通知)),仍然有开销。select调用需要传入 fd 数组,需要拷贝一份到内核,高并发场景下这样的拷贝消耗的资源是惊人的。(可优化为不复制)
4、select并没有通知用户态哪一个socket有数据,仍然需要O(n)的遍历。select 仅仅返回可读文件描述符的个数,具体哪个可读还是要用户自己遍历。(可优化为只返回给用户就绪的文件描述符,无需用户做无效的遍历)
---那为什么要先先对rset进行置位,后面又对它进行遍历,要搞两次?select要把所有的读写的socket的文件描述符都传进去吗?然后谁要读写就返回?


你提到的关于 `select` 的一些限制和开销都是正确的。`select` 确实有一些设计上的限制和效率问题,这也是为什么在处理大量并发连接时,我们更倾向于使用 `poll` 或 `epoll` 等更高效的 I/O 多路复用机制。让我们详细探讨一下这些问题,并解释为什么 `select` 需要进行两次操作。

### `select` 的工作原理

`select` 是一种 I/O 多路复用机制,允许程序监控多个文件描述符,等待其中的一个或多个变为可读、可写或发生异常。`select` 的工作流程大致如下:

1. **初始化文件描述符集合**:程序将需要监控的文件描述符添加到一个或多个集合中(如读集合 `rset`、写集合 `wset` 和异常集合 `eset`)。
2. **调用 `select`**:程序调用 `select` 函数,将这些文件描述符集合传递给内核。
3. **内核检查状态**:内核检查所有传入的文件描述符的状态,标记那些已经准备好进行 I/O 操作的文件描述符。
4. **返回结果**:`select` 返回一个整数,表示有多少文件描述符已经准备好进行 I/O 操作。程序需要遍历这些集合,找到那些已经准备好的文件描述符。

### `select` 的一些限制

1. **文件描述符数量限制**:`select` 使用一个固定大小的位图(bitmap)来表示文件描述符集合,通常最大为 1024 位。这意味着一个进程最多只能同时监控 1024 个文件描述符。
2. **不可重用的集合**:每次调用 `select` 后,文件描述符集合会被修改,需要重新初始化。
3. **内存复制开销**:`select` 需要将文件描述符集合从用户态复制到内核态,这在高并发场景下会带来显著的开销。
4. **O(n) 的遍历**:`select` 返回后,程序需要遍历所有文件描述符集合,找到那些已经准备好的文件描述符,这会带来额外的开销。

### 为什么需要两次操作

1. **初始化和传递文件描述符集合**:在调用 `select` 之前,程序需要将所有需要监控的文件描述符添加到集合中。这是第一次操作。
2. **遍历和处理结果**:`select` 返回后,程序需要遍历文件描述符集合,找到那些已经准备好的文件描述符并进行处理。这是第二次操作。

### `select` 的调用过程

当调用 `select` 时,程序需要传入三个文件描述符集合(读、写、异常)以及一个超时时间。内核会检查这些集合中的每个文件描述符的状态,并将那些已经准备好的文件描述符标记出来。`select` 返回后,程序需要遍历这些集合,找到那些已经准备好的文件描述符进行处理。

### 示例代码

以下是一个简单的 `select` 使用示例:

```c
#include <sys/select.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    fd_set readfds;
    struct timeval timeout;
    int fd = 0; // 监控标准输入(文件描述符 0)

    // 初始化文件描述符集合
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);

    // 设置超时时间
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    // 调用 select
    int ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
    if (ret == -1) {
        perror("select");
        return 1;
    } else if (ret == 0) {
        printf("Timeout occurred! No data after 5 seconds.\n");
    } else {
        if (FD_ISSET(fd, &readfds)) {
            printf("Data is available to read.\n");
        }
    }

    return 0;
}
```

### 结论

`select` 需要进行两次操作:第一次是初始化和传递文件描述符集合,第二次是遍历和处理结果。这种设计带来了一些效率问题和限制,如文件描述符数量限制、内存复制开销和 O(n) 的遍历。为了克服这些问题,在处理大量并发连接时,我们更倾向于使用更高效的 I/O 多路复用机制,如 `poll` 和 `epoll`。


========你的例子里面,用户进程是在读还是写,如果是读,怎么没有看到处理读出来的结果的代码?如何解释结果?
你说得对,我之前提供的示例代码确实没有包含实际的读取操作。让我们扩展这个示例,添加读取操作以便更好地理解 `select` 的工作流程。

在这个扩展的示例中,我们将监控标准输入(文件描述符 0),并在有数据可读时读取数据并进行处理。

### 扩展示例:读取标准输入的数据

```c
#include <sys/select.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    fd_set readfds;
    struct timeval timeout;
    int fd = 0; // 监控标准输入(文件描述符 0)
    char buffer[1024];
    int bytesRead;

    while (1) {
        // 初始化文件描述符集合
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);

        // 设置超时时间
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        // 调用 select
        int ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
        if (ret == -1) {
            perror("select");
            return 1;
        } else if (ret == 0) {
            printf("Timeout occurred! No data after 5 seconds.\n");
        } else {
            if (FD_ISSET(fd, &readfds)) {
                // 读取数据
                bytesRead = read(fd, buffer, sizeof(buffer) - 1);
                if (bytesRead < 0) {
                    perror("read");
                    return 1;
                }
                buffer[bytesRead] = '\0'; // 确保字符串以 null 结尾
                printf("Read %d bytes: %s\n", bytesRead, buffer);
            }
        }
    }

    return 0;
}
```

### 代码解释

1. **初始化文件描述符集合**:
   - 使用 `FD_ZERO` 清空文件描述符集合。
   - 使用 `FD_SET` 将标准输入(文件描述符 0)添加到集合中。

2. **设置超时时间**:
   - 设置超时时间为 5 秒。

3. **调用 `select`**:
   - `select` 函数的第一个参数是文件描述符集合中最大文件描述符加 1。
   - `select` 会阻塞直到文件描述符集合中的一个或多个文件描述符变为可读、可写或发生异常,或者超时时间到达。

4. **处理 `select` 的返回值**:
   - 如果 `select` 返回 -1,表示发生错误。
   - 如果 `select` 返回 0,表示超时,没有文件描述符变为就绪状态。
   - 如果 `select` 返回正数,表示有文件描述符变为就绪状态。

5. **读取数据**:
   - 使用 `FD_ISSET` 检查标准输入是否可读。
   - 如果标准输入可读,使用 `read` 函数读取数据,并将读取的数据打印出来。

### 结论

这个扩展示例展示了如何使用 `select` 来监控标准输入,并在有数据可读时读取数据并进行处理。通过这种方式,程序可以同时监控多个文件描述符,并在任何一个文件描述符变为就绪状态时进行相应的处理。

希望这个示例能够更好地帮助你理解 `select` 的工作流程和如何处理读取的数据。如果你有更多问题或需要进一步的解释,请随时告诉我!

====那用户态程序不是要不停的循环来检查是否有结果了?

是的,使用 `select` 等传统 I/O 多路复用机制时,用户态程序确实需要在一个循环中反复调用 `select` 来检查是否有文件描述符变为就绪状态。这种模式通常被称为“事件循环”或“主循环”。这个循环会一直运行,直到程序终止。

### 事件循环的基本结构

一个典型的事件循环的结构如下:

1. **初始化**:设置文件描述符集合、超时时间等。
2. **循环**:反复调用 `select` 来检查文件描述符的状态,并在有事件发生时进行处理。
3. **处理事件**:根据 `select` 返回的结果,处理相应的 I/O 事件。

### 示例代码

以下是一个更完整的示例,展示了如何使用 `select` 在事件循环中处理多个文件描述符:

```c
#include <sys/select.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_CLIENTS 10

int main() {
    fd_set readfds;
    struct timeval timeout;
    int max_fd;
    int client_fds[MAX_CLIENTS];
    char buffer[1024];
    int bytesRead;

    // 初始化客户端文件描述符数组
    for (int i = 0; i < MAX_CLIENTS; i++) {
        client_fds[i] = -1;
    }

    // 添加标准输入到客户端文件描述符数组中
    client_fds[0] = 0; // 标准输入

    while (1) {
        // 初始化文件描述符集合
        FD_ZERO(&readfds);
        max_fd = -1;

        // 将客户端文件描述符添加到集合中
        for (int i = 0; i < MAX_CLIENTS; i++) {
            if (client_fds[i] != -1) {
                FD_SET(client_fds[i], &readfds);
                if (client_fds[i] > max_fd) {
                    max_fd = client_fds[i];
                }
            }
        }

        // 设置超时时间
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        // 调用 select

===============

===============

事件循环的优化

上面的示例代码展示了一个基本的事件循环结构,但在实际应用中,可以对其进行一些优化:

  1. 减少不必要的集合初始化:

    • 在每次循环中,不需要完全重新初始化文件描述符集合。
    • 可以只更新需要修改的部分,比如新添加或删除的文件描述符。
  2. 使用边缘触发(Edge-Triggered)模式:

    • 如果使用epoll作为I/O多路复用机制,可以采用边缘触发模式。
    • 这种模式下,只有当文件描述符的状态发生变化时,epoll_wait才会返回,避免了不必要的系统调用。
  3. 异步通知机制:

    • 某些I/O多路复用机制,如epoll,支持异步通知,无需轮询检查。
    • 当有事件发生时,内核会主动通知应用程序,减少了不必要的系统调用开销。
  4. 批量处理事件:

    • 当有多个文件描述符就绪时,可以一次性处理所有就绪的描述符,而不是逐个处理。
    • 这样可以减少系统调用的次数,提高整体性能。
  5. 非阻塞I/O:

    • 使用非阻塞I/O可以进一步优化事件循环。
    • 当某个文件描述符没有数据可读时,应用程序可以立即返回,而不是阻塞等待。

通过采用这些优化技巧,可以大幅提高基于事件循环的I/O多路复用应用程序的性能和scalability。

Redis中的事件循环优化

Redis就是一个典型的采用了上述优化技巧的高性能网络服务器。在Redis的事件循环中,主要有以下几个优化点:

  1. 使用epoll的边缘触发模式:

    • Redis使用epoll作为I/O多路复用机制,并采用边缘触发模式。
    • 这样可以最大限度地减少不必要的系统调用。
  2. 异步通知机制:

    • Redis的事件循环利用epoll的异步通知机制,无需主动轮询检查。
    • 当有事件发生时,epoll会主动通知Redis的事件处理器。
  3. 批量处理事件:

    • Redis的事件处理器会一次性处理所有就绪的文件描述符,减少系统调用开销。
  4. 非阻塞I/O:

    • Redis的网络I/O操作采用非阻塞模式,当某个文件描述符没有数据可读时,可以立即返回。

通过上述优化,Redis的事件循环能够高效地处理大量的并发客户端连接,为Redis提供了出色的性能和scalability。

总结

I/O多路复用机制,如select、poll和epoll,是实现高性能网络服务器的关键技术。在使用这些机制时,事件循环是一个非常重要的模式。通过采用各种优化技巧,如减少集合初始化、使用边缘触发模式、异步通知机制、批量处理事件以及非阻塞I/O,可以大幅提高事件循环的性能和scalability。

Redis就是一个成功利用了这些优化技巧的高性能网络服务器。通过深入理解I/O多路复用和事件循环的工作原理,我们可以设计出更加高效和可扩展的网络应用程序。

异步I/O编程模型的演化

除了传统的基于事件循环的I/O多路复用模型,近年来还出现了一些新的异步I/O编程模型,它们进一步提高了开发效率和性能。让我们来看看这些新兴的异步I/O编程模型:

  1. Futures/Promises:

    • Futures/Promises是一种抽象,用于表示异步操作的结果。
    • 开发者可以注册回调函数,在异步操作完成时得到通知。
    • Futures/Promises提供了更优雅的编程模型,避免了传统回调地狱的问题。
  2. Async/Await:

    • Async/Await是一种基于Futures/Promises的语法糖,提供了更加同步的编程体验。
    • 开发者可以使用asyncawait关键字编写异步代码,就像编写同步代码一样。
    • Async/Await大大简化了异步I/O编程,提高了代码的可读性和可维护性。
  3. Reactor模式:

    • Reactor模式是一种事件驱动的异步I/O编程模式。
    • 它将I/O操作的处理与I/O事件的分派解耦,使得应用程序的逻辑更加清晰。
    • Reactor模式广泛应用于高性能网络服务器的开发,如Nginx、Netty等。
  4. Proactor模式:

    • Proactor模式是Reactor模式的一种变体,它将I/O操作的发起与I/O操作的完成解耦。
    • Proactor模式适用于需要执行长时间I/O操作的场景,如文件I/O、数据库I/O等。
    • Proactor模式可以更好地利用异步I/O操作的优势,提高应用程序的吞吐量。

这些新兴的异步I/O编程模型,如Futures/Promises、Async/Await、Reactor和Proactor,都旨在提高异步I/O编程的效率和可维护性。它们建立在传统I/O多路复用机制的基础之上,进一步抽象和简化了异步I/O编程的复杂性。

异步I/O编程模型在Redis中的应用

Redis也采用了一些新兴的异步I/O编程模型:

  1. Reactor模式:

    • Redis的事件循环采用了Reactor模式,将I/O事件的分派与事件处理逻辑解耦。
    • 这使得Redis的事件处理代码更加清晰和可维护。
  2. Futures/Promises:

    • Redis内部使用了一些Futures/Promises的抽象,如用于处理异步命令的RedisCommandFuture
    • 这些抽象帮助Redis开发者更好地管理异步操作的结果和错误处理。
  3. Async/Await:

    • Redis的Lua脚本支持使用Async/Await语法,使得编写异步I/O代码更加简单和直观。
    • 这使得Redis的扩展性和可编程性得到了进一步增强。

通过采用这些新兴的异步I/O编程模型,Redis不仅能够利用底层的I/O多路复用机制提高性能,还能够提供更加优雅和可维护的编程接口,方便开发者进行扩展和二次开发。

未来发展趋势

随着计算硬件的不断进化,以及对高性能和可扩展性的需求不断增加,I/O多路复用技术和异步I/O编程模型将会继续发展和完善。一些未来的发展趋势包括:

  1. 硬件加速:

    • 未来可能会出现专门用于I/O多路复用的硬件加速器,进一步提高性能。
    • 这种硬件加速器可以与操作系统内核深度集成,为应用程序提供更高效的I/O服务。
  2. 新的I/O多路复用机制:

    • 除了现有的epoll、kqueue等机制,未来可能会出现更加高效和灵活的I/O多路复用机制。
    • 这些新机制可能会进一步降低I/O操作的开销,并提供更丰富的事件通知功能。
  3. 更高级的异步I/O编程模型:

    • Futures/Promises和Async/Await只是异步I/O编程模型发展的一个阶段。
    • 未来可能会出现更加抽象和强大的异步I/O编程模型,进一步简化异步代码的编写和维护。
  4. 与云计算的深度集成:

    • 随着云计算的发展,I/O多路复用技术和异步I/O编程模型将与云基础设施深度集成。
    • 这将使得云端应用程序能够更好地利用底层的I/O资源,提高整体的性能和可扩展性。

总的来说,I/O多路复用技术和异步I/O编程模型将会继续发展,为未来的高性能、可扩展的网络应用程序提供更加强大和灵活的支持。Redis等先驱应用程序的实践,为这一发展方向提供了有价值的经验和启示。

异步I/O编程模型的进一步改进

除了前面提到的Futures/Promises、Async/Await、Reactor和Proactor模式,近年来还出现了一些更加先进的异步I/O编程模型,它们进一步提高了开发效率和性能。让我们来看看这些新的编程模型:

  1. Coroutines:

    • Coroutines是一种轻量级的并发编程机制,允许程序暂停执行并稍后恢复。
    • 与传统的线程相比,Coroutines的切换开销更小,更适合实现异步I/O编程。
    • 一些编程语言,如Python的async/await、Go的goroutine等,都内置了对Coroutines的支持。
  2. Reactive Streams:

    • Reactive Streams是一种基于事件流的编程模型,适用于异步非阻塞数据处理。
    • 它提供了一组标准的接口和语义,使得不同的库和框架可以相互集成。
    • Reactive Streams被广泛应用于事件驱动的应用程序,如实时数据处理、流媒体等。
  3. Actor模型:

    • Actor模型是一种基于消息传递的并发编程模型,每个Actor都是一个独立的执行单元。
    • Actor之间通过异步发送消息进行通信,这种模型非常适合于实现高并发的分布式系统。
    • Actor模型被应用于构建高性能、可扩展的网络服务器,如Akka、Erlang/OTP等。
  4. 无锁并发编程:

    • 无锁并发编程技术,如RCU(Read-Copy-Update)、hazard pointers等,可以进一步优化异步I/O编程的性能。
    • 这些技术避免了传统锁机制的开销,在高并发场景下表现更加出色。
    • 无锁并发编程技术被广泛应用于操作系统内核、数据库引擎等对性能要求极高的系统中。

这些新兴的异步I/O编程模型,如Coroutines、Reactive Streams、Actor模型和无锁并发编程,都旨在进一步提高异步I/O编程的效率和可维护性。它们建立在传统I/O多路复用机制的基础之上,并提供了更高级的抽象和编程接口。

异步I/O编程模型在Redis中的应用

Redis也在不断吸收和应用这些新兴的异步I/O编程模型:

  1. Coroutines:

    • Redis的Lua脚本支持使用Coroutines,允许开发者编写更加简洁和高效的异步I/O代码。
    • Coroutines的轻量级特性非常适合Redis这种高并发的场景。
  2. Reactive Streams:

    • Redis的复制和集群特性,部分采用了基于Reactive Streams的编程模型。
    • 这使得Redis的分布式特性实现更加优雅和可扩展。
  3. Actor模型:

    • Redis的Cluster模式,利用了Actor模型的消息传递机制来实现节点间的协调和通信。
    • Actor模型的异步特性非常适合于Redis这种高并发、高可用的分布式系统。
  4. 无锁并发编程:

    • Redis内部大量使用了无锁并发编程技术,如RCU,以提高并发性能。
    • 这些技术帮助Redis在高并发场景下保持出色的性能表现。

通过采用这些新兴的异步I/O编程模型,Redis不仅能够利用底层的I/O多路复用机制提高性能,还能够提供更加优雅和可扩展的编程接口,方便开发者进行二次开发和扩展。

未来发展趋势

随着计算硬件的不断进化,以及对高性能和可扩展性的需求不断增加,I/O多路复用技术和异步I/O编程模型将会继续发展和完善。一些未来的发展趋势包括:

  1. 硬件加速:

    • 未来可能会出现专门用于I/O多路复用的硬件加速器,进一步提高性能。
    • 这种硬件加速器可以与操作系统内核深度集成,为应用程序提供更高效的I/O服务。
  2. 新的I/O多路复用机制:

    • 除了现有的epoll、kqueue等机制,未来可能会出现更加高效和灵活的I/O多路复用机制。
    • 这些新机制可能会进一步降低I/O操作的开销,并提供更丰富的事件通知功能。
  3. 更高级的异步I/O编程模型:

    • Coroutines、Reactive Streams和Actor模型只是异步I/O编程模型发展的一个阶段。
    • 未来可能会出现更加抽象和强大的异步I/O编程模型,进一步简化异步代码的编写和维护。
  4. 与云计算的深度集成:

    • 随着云计算的发展,I/O多路复用技术和异步I/O编程模型将与云基础设施深度集成。
    • 这将使得云端应用程序能够更好地利用底层的I/O资源,提高整体的性能和可扩展性。
  5. 边缘计算的兴起:

    • 随着边缘计算的兴起,I/O多路复用技术和异步I/O编程模型将在边缘设备上发挥重要作用。
    • 这些技术可以帮助边缘设备高效地处理大量的并发I/O操作,为边缘计算应用提供强大的支撑。

总的来说,I/O多路复用技术和异步I/O编程模型将会继续发展,为未来的高性能、可扩展的网络应用程序提供更加强大和灵活的支持。Redis等先驱应用程序的实践,为这一发展方向提供了有价值的经验和启示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/56825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

003 优秀学员统计

003 优秀学员统计 题目描述 公司某部门软件教导团正在组织新员工每日打卡学习活动&#xff0c;他们开展这项学习活动已经一个月了&#xff0c;所以想统计一下这个月优秀的打卡员工。每个员工对应一个id&#xff0c;每天的打卡记录当天打卡的员工的id集合&#xff0c;一共30天…

【Windows】电脑端口明明没有进程占用但显示端口被占用(动态端口)

TOC 一、问题 重启电脑后&#xff0c;启用某个服务显示1089端口被占用。 查看是哪个进程占用了&#xff1a; netstat -aon | findstr "1089"没有输出&#xff0c;但是换其他端口&#xff0c;是可以看到相关进程的&#xff1a; 现在最简单的方式是给我的服务指定另…

解決爬蟲代理連接的方法

爬蟲在運行過程中常常會遇到代理連接的問題&#xff0c;這可能導致數據抓取的效率降低甚至失敗。 常見的代理連接問題 代理IP失效&#xff1a;這是最常見的問題之一。有些代理IP可能在使用一段時間後失效&#xff0c;導致連接失敗。 連接超時&#xff1a;由於網路不穩定或代…

阿里云项目启动OOM问题解决

问题描述 随着项目业务的增长&#xff0c;系统启动时内存紧张&#xff0c;每次第一次启动的时候就会出现oom第二次或者第n的时候&#xff0c;就启动成功了。 带着这个疑问&#xff0c;我就在阿里云上提交了工单&#xff0c;咨询为什么第一次提交失败但是后面却能提交成功尼&a…

HarmonyOS 组件样式@Style 、 @Extend、自定义扩展(AttributeModifier、AttributeUpdater)

1. HarmonyOS Style 、 Extend、自定义扩展&#xff08;AttributeModifier、AttributeUpdater&#xff09; Styles装饰器&#xff1a;定义组件重用样式   ;Extend装饰器&#xff1a;定义扩展组件样式   自定义扩展&#xff1a;AttributeModifier、AttributeUpdater 1.1. 区…

SpringBoot 下的Excel文件损坏与内容乱码问题

序言 随着打包部署的方式的改变&#xff0c;原本正常运行的代码可能带来一些新的问题&#xff0c;比如我们现在使用SpringBoot 的方式生成Jar包直接运行&#xff0c;就会对我们再在Resource下的Excel文件产生影响&#xff0c;导入与预期不符的情况发生cuiyaonan2000163.com 比…

Educational Codeforces Round 170 C New Game

思路 滑动窗口 排完序后找左右边界差值小于等于k 的最长子序列长度即可 可以用map去重 代码 #include <bits/stdc.h> using namespace std;const int N 200010;int t, n, k; int a[N], b[N];void solve() {cin >> n >> k;for (int i 1; i < n; i …

计算机网络的主要知识点小结

计算机网络是指将多台计算机通过通信线路连接起来&#xff0c;实现资源共享和信息传递的系统。 一、计算机网络概述 1. 定义和功能 - 定义&#xff1a;计算机网络是将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操…

Anchor DETR论文笔记

原文链接 [2109.07107] Anchor DETR: Query Design for Transformer-Based Object Detection (arxiv.org)https://arxiv.org/abs/2109.07107 原文笔记 What 提出了一种新的基于锚点的查询设计&#xff0c;即将锚点编码为对象查询。 Why 对象检测任务是预测图像中每个对象…

Python基础知识-异常处理篇

在Python中&#xff0c;异常处理是应对程序运行时错误的一种机制。它能帮助我们捕获和处理错误&#xff0c;防止程序崩溃。下面是异常处理的关键知识和实践示例&#xff1a; 1. 异常处理基础 Python中的异常处理使用 try, except, else, 和 finally 块来实现。 基本语法结构…

SQLite Having 子句

SQLite Having 子句 在SQLite数据库中&#xff0c;HAVING子句用于与GROUP BY子句配合使用&#xff0c;以便对分组后的结果进行条件过滤。当您需要对分组的数据应用条件时&#xff0c;HAVING子句变得非常有用。这与WHERE子句不同&#xff0c;后者用于在数据分组之前过滤行。 基…

el-table相关的功能实现

1. 表格嵌套表格时&#xff0c;隐藏父表格的全选框 场景&#xff1a;当table表格设置复选&#xff08;多选&#xff09;功能时&#xff0c;如何隐藏表头的复选框&#xff0c;不让用户一键多选。 <el-table :header-cell-class-name"cellClass">// 表头复选框禁…

通过HBase实现大规模日志数据存储与分析

通过HBase实现大规模日志数据存储与分析 I. 项目背景 随着互联网技术的迅速发展&#xff0c;各类应用和系统每天都会生成大量的日志数据。这些日志包括应用日志、服务器日志、数据库日志、安全日志等&#xff0c;它们不仅记录了系统的运行状况&#xff0c;还包含了许多关键的…

[NeetCode 150] Minimum Window With Characters

Minimum Window With Characters Given two strings s and t, return the shortest substring of s such that every character in t, including duplicates, is present in the substring. If such a substring does not exist, return an empty string “”. You may assum…

Apache HttpClient 和 OkHttpClient 的使用

概述 Apache HttpClient Apache HttpClient是一个开源的HTTP客户端库&#xff0c;提供了丰富的HTTP通信功能。它支持HTTP/1.1和HTTPS协议&#xff0c;具有连接池管理、重试机制、代理设置等高级特性。HttpClient的API设计虽然相对繁琐&#xff0c;但提供了高度的可配置性和灵…

Flutter主题最佳实践

Styling your Flutter app not only makes it visually appealing but also enhances the user experience. Flutter offers a robust theming system that helps you maintain consistency and customize your app’s look and feel. 设计 Flutter 应用程序的风格不仅能使其在…

E - Permute K times 2

E - Permute K times 2 思路 这题由于序列P是一个排列&#xff0c;所以将P表示成一个图的时候&#xff0c;这个图将由 m m m个环构成 对于每个环上的点来说&#xff0c;第一回合它会移动到距离它为 2 2 2的点上&#xff0c;距离它为 2 2 2的点同时也以相同的方式移动&#x…

机器视觉-相机、镜头、光源(总结)

目录 1、机器视觉光源概述 2、光源的作用 3、光谱 4、工业场景常见光源 4.1、白炽灯 4.2、卤素灯 4.3、 荧光灯 4.4、LED灯 4.5、激光灯 5、光源的基本性能 5.1、光通量 5.2、光效率 5.3、发光强度 5.4、光照度 5.5、均匀性 5.6、色温 5.7、显色性 6、基本光学…

【Linux | 网络I/O模型】五种网络I/O模型详解

1、数据传输过程 在 Linux 系统中&#xff0c;数据传输是通过 I/O 操作来实现的。I/O 操作是指数据从应用程序到内核&#xff0c;再到硬件设备&#xff08;如磁盘、网络接口&#xff09;的过程。 操作系统为了保护自己&#xff0c;设计了用户态、内核态两个状态。应用程序一般工…

基于云平台的智能家居管理系统设计与通信协议分析

案例 阅读以下关于 Web 系统架构设计的教述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某公司拟开发一个智能家居管理系统&#xff0c;该系统的主要功能需求如下: 1)用户可使用该系统客户端实现对家居设备的控制&#xff0c;且家居设备可向客户端反馈实时状态&#x…