IO 多路复用技术:原理、类型及 Go 实现

文章目录

    • 1. 引言
      • IO 多路复用的应用场景与重要性
      • 高并发下的 IO 处理挑战
    • 2. IO 多路复用概述
      • 什么是 IO 多路复用
      • IO 多路复用的优点与适用场景
    • 3. IO 多路复用的三种主要实现
      • 3.1 `select`
      • 3.2 `poll`
      • 3.3 `epoll`
      • 三者对比
    • 4. 深入理解 epoll
      • 4.1 epoll 的三大操作
      • 4.2 epoll 的核心数据结构
      • 4.3 边缘触发与水平触发模式详解
        • 1. 水平触发(LT)
        • 2. 边缘触发(ET)
      • 4.4 水平触发和边缘触发的对比
    • 5. Go 实现一个简单的聊天室服务器
      • 5.1 实现思路
      • 5.2 使用 `epoll` 管理客户端连接
      • 5.3 代码实现
      • 5.4 代码解析
      • 5.5 边缘触发的关键点
      • 5.6 流程图:事件处理流程
    • 6. 总结
    • 结束语


1. 引言

IO 多路复用的应用场景与重要性

在网络编程中,服务器需要同时处理多个客户端的请求,这在高并发环境中尤为突出。举例来说,大型即时通讯应用、HTTP 服务器、数据库服务等场景下,往往要支持成千上万个客户端的连接。如果每个客户端连接都使用一个独立的线程,系统资源消耗会极为庞大,并导致频繁的线程切换,严重影响性能。

IO 多路复用技术则是一种可以在单线程中管理多个 IO 事件的高效机制。通过在单线程中监控多个文件描述符(通常是 socket)上的 IO 操作状态,服务器能够灵活处理多个客户端的请求,避免了线程和资源的大量开销。因此,IO 多路复用广泛应用于高并发服务器编程中,如 Nginx、Redis、Kafka 等项目中。


高并发下的 IO 处理挑战

高并发场景中,服务器面临的主要挑战包括:

  • 资源管理难度:大量线程带来的 CPU 资源开销和内存管理负担。
  • 性能瓶颈:传统阻塞 IO 导致的频繁等待,降低了系统的吞吐量。
  • 复杂的事件处理:如何在不增加复杂度的前提下高效管理多客户端连接。

IO 多路复用技术通过提供非阻塞、集中管理的方式有效解决了以上问题。理解 IO 多路复用技术及其实现原理,尤其是高效的 epoll,对网络编程的开发者非常重要。


2. IO 多路复用概述

什么是 IO 多路复用

IO 多路复用是一种在一个线程中同时监听多个 IO 事件的方法。当任何一个文件描述符上有数据可读或可写时,IO 多路复用会通知应用程序去处理该事件。常见的 IO 多路复用包括 selectpollepoll

IO 多路复用的优点与适用场景

  • 高效资源利用:一个线程管理多个连接,减少了多线程的切换开销。
  • 灵活性:可以动态增加或减少监控的文件描述符,适应高并发需求。
  • 提高吞吐量:通过减少阻塞等待,提高了数据处理的整体吞吐量。

适用场景:IO 多路复用特别适合长连接、大量连接、并发请求频繁的场景,如 Web 服务器、聊天室服务、数据库服务等。


3. IO 多路复用的三种主要实现

在 Linux 系统中,IO 多路复用有三种实现方式:selectpollepoll。这三种方法在原理、性能和适用场景上存在显著差异。

3.1 select

select 是最早的 IO 多路复用实现,广泛支持于多种操作系统。

select 的基本工作方式是通过文件描述符集合来管理多个 IO 通道。应用程序在调用 select 时,需要传入一个文件描述符集合(如读集合、写集合和异常集合),select 会阻塞并等待其中任何一个文件描述符的状态发生变化。如果有 IO 事件发生,select 返回相应的描述符集合,供程序进一步处理。

特点:

  • 文件描述符限制select 受文件描述符数量的限制,通常 FD_SETSIZE 设定为 1024,意味着 select 最多只能同时监控 1024 个文件描述符。
  • 性能问题select 在每次调用时都会遍历整个文件描述符集合,检查是否有事件发生,因此性能较低,尤其在高并发场景中,效率更低。

适用场景:由于性能瓶颈和文件描述符限制,select 适用于小规模并发的网络应用,通常是一些简单的服务或学习用途。


3.2 poll

poll 是对 select 的改进,消除了文件描述符数量限制,并提高了一定的性能。

基本原理:与 select 类似,poll 通过遍历文件描述符集合来检查 IO 事件,但它使用链表来存储文件描述符,因此文件描述符的数量不再受 FD_SETSIZE 限制,理论上可以监控更多的连接。

特点:

  • 消除了文件描述符上限poll 允许监控大量的文件描述符。
  • 性能问题仍然存在:与 select 类似,poll 每次调用仍需遍历整个文件描述符集合,因此在大并发场景下效率较低。

适用场景:适合中等规模的并发网络应用,但在高并发环境下,性能依然有限。


3.3 epoll

epoll 是 Linux 提供的高效 IO 多路复用方式,专门为大规模并发场景而设计。

epoll 的工作方式与 selectpoll 有显著不同epoll 使用事件通知机制,即在文件描述符有状态变化时,epoll 将只返回变化的文件描述符,而不是遍历整个文件描述符集合。

epoll 提供了以下三种核心操作:

  1. epoll_create:创建一个 epoll 实例,用于管理多个文件描述符。
  2. epoll_ctl:添加、修改或删除 epoll 实例中的文件描述符事件。
  3. epoll_wait:等待事件触发,并返回已经就绪的事件集合。

epoll 的优势在于:

  • O(1) 复杂度:每次事件触发后,epoll 只返回变化的文件描述符,避免了重复遍历整个集合的开销。
  • 红黑树和就绪链表epoll 使用红黑树存储监控的文件描述符,同时将就绪的事件放入就绪链表,以便高效管理和返回事件。

三者对比

特性selectpollepoll
文件描述符限制受限(通常为 1024 个)无限制无限制
实现方式文件描述符集合链表红黑树 + 就绪链表
性能随并发数增加而降低随并发数增加而降低O(1) 性能
适用场景小规模并发中等规模并发大规模并发,适合高性能场景

通过 epoll,高并发服务器能够在单线程中处理数万个并发连接,因此它被广泛用于各类高性能服务器中。接下来我们将深入探讨 epoll 的核心数据结构和触发机制。


4. 深入理解 epoll

在理解了 epoll 的基本原理后,我们需要深入其核心实现,了解数据结构、触发机制等,尤其是边缘触发和水平触发模式。让我们详细分解 epoll 的工作机制及其在高并发场景中的优势。

4.1 epoll 的三大操作

  1. epoll_create:创建 epoll 实例并初始化相关数据结构。这个实例相当于一个事件管理器,用于集中管理各个文件描述符的事件状态。

    epollFD, err := syscall.EpollCreate1(0)
    if err != nil {panic(err)
    }
    defer syscall.Close(epollFD)
    
  2. epoll_ctlepoll 控制接口,用于向 epoll 实例中添加、修改或删除文件描述符的事件监听。

    event := syscall.EpollEvent{Events: syscall.EPOLLIN, Fd: int32(fd)}
    err := syscall.EpollCtl(epollFD, syscall.EPOLL_CTL_ADD, fd, &event)
    if err != nil {panic(err)
    }
    
  3. epoll_wait:阻塞等待事件触发,并将就绪的文件描述符返回给用户。

    events := make([]syscall.EpollEvent, 10) // 创建事件集合
    nfds, err := syscall.EpollWait(epollFD, events, -1)
    if err != nil {panic(err)
    }
    

4.2 epoll 的核心数据结构

epoll 使用两种关键数据结构来管理和维护文件描述符事件的状态:

  • 红黑树(rbtree):所有被监控的文件描述符存储在红黑树中,以便进行快速查找、插入和删除操作。当我们调用 epoll_ctl 添加或删除文件描述符时,epoll 会操作红黑树。

  • 就绪链表:当某个文件描述符的状态发生变化时,epoll 会将它添加到就绪链表中。每次调用 epoll_wait 时,epoll 会将链表中的就绪事件返回,而不再遍历整个红黑树。

4.3 边缘触发与水平触发模式详解

epoll 中,事件通知有两种模式:水平触发(Level Triggered, LT)边缘触发(Edge Triggered, ET)。两种触发模式决定了 epoll 如何通知应用程序处理 IO 事件。

1. 水平触发(LT)

水平触发是 epoll 的默认模式,也是最常见的触发模式。水平触发模式下,只要文件描述符处于就绪状态(例如,缓冲区中有数据可以读取),epoll_wait 就会不断返回该事件。这意味着应用程序可以多次获取并处理同一个就绪的文件描述符事件,直到事件处理完毕。

流程图:
水平触发

工作机制:

  1. 文件描述符状态变化时触发:每次调用 epoll_wait 时,若文件描述符处于就绪状态,epoll 会将其返回。
  2. 重复通知:如果应用程序没有处理文件描述符的就绪状态(例如,读取完所有数据),epoll_wait 会在下一次调用时再次返回该文件描述符,直到就绪状态被清除(例如,数据被完全读取)。

优缺点:

  • 优点:简单,适合处理大量 IO 事件,因为不会错过任何就绪事件。
  • 缺点:会重复返回同一个事件,增加了系统调用次数,性能可能受影响。

示例:水平触发读取数据

以下是一个使用水平触发读取数据的示例:

func handleEventsLT(epollFD int, events []syscall.EpollEvent, clients map[int]net.Conn) {for _, event := range events {if event.Events&syscall.EPOLLIN != 0 {fd := int(event.Fd)buf := make([]byte, 512)// 循环读取数据直到读完为止for {n, err := clients[fd].Read(buf)if n == 0 || err != nil {// 如果读取完或遇到错误,关闭连接fmt.Printf("Closing connection %d\n", fd)syscall.EpollCtl(epollFD, syscall.EPOLL_CTL_DEL, fd, nil)clients[fd].Close()delete(clients, fd)break}fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n]))// 这里可以处理读取到的数据,比如广播到其他客户端}}}
}

在水平触发模式中,上述代码会在文件描述符仍有未处理的数据时不断被触发,确保我们可以持续读取到数据,直到全部读完。

2. 边缘触发(ET)

边缘触发是一种高效的触发模式,适合性能要求高的场景。与水平触发不同,边缘触发仅在文件描述符状态发生边缘变化时(例如,从不可读到可读)通知一次。也就是说,如果缓冲区有新数据到达,epoll 会通知一次,而不会持续通知。

边缘触发时序图:
边缘触发

工作机制:

  1. 状态变化时触发:边缘触发只在文件描述符的状态从不可读到可读、或不可写到可写时通知一次。
  2. 不重复通知:如果应用程序在收到通知后没有将数据读完,那么在数据再次变化前不会收到新的通知。这意味着应用程序必须一次性将数据全部读取,否则会错过后续的事件通知。

优缺点:

  • 优点:减少了重复通知,性能更高,适合高并发场景。
  • 缺点:开发难度更高。应用程序必须一次性将数据读完,否则可能错过事件通知,导致数据读取不完整。

示例:边缘触发读取数据:

为了在边缘触发模式下保证数据不遗漏,我们通常会使用非阻塞模式,并在单次事件触发中循环读取数据直到缓冲区为空。

func handleEventsET(epollFD int, events []syscall.EpollEvent, clients map[int]net.Conn) {for _, event := range events {if event.Events&syscall.EPOLLIN != 0 {fd := int(event.Fd)buf := make([]byte, 512)// 边缘触发模式下,必须一次性读完所有数据for {n, err := clients[fd].Read(buf)if n == 0 || err != nil {if err != nil && err != syscall.EAGAIN {// 出现非阻塞错误或读到 EOF,关闭连接fmt.Printf("Closing connection %d\n", fd)syscall.EpollCtl(epollFD, syscall.EPOLL_CTL_DEL, fd, nil)clients[fd].Close()delete(clients, fd)}break}fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n]))// 处理读取到的数据}}}
}

在此代码中,循环读取数据直到返回 EAGAIN 错误或数据读完。通过这种方式,确保我们在一次事件触发中尽可能多地读取数据,避免漏掉数据。


4.4 水平触发和边缘触发的对比

特点水平触发(LT)边缘触发(ET)
触发条件只要文件描述符处于就绪状态,持续触发状态从不可用变为可用时触发一次
重复通知会持续返回相同的事件,直到状态改变不会重复通知
性能较低较高
实现复杂度简单较高
适用场景适合一般场景,特别是低并发或对性能要求不高的场景适合高并发场景,性能要求高
  1. 一般场景(水平触发):水平触发模式适合大部分 IO 操作,因为它简单可靠。尤其在低并发场景下,水平触发模式便于实现,不容易遗漏事件。
  2. 高性能场景(边缘触发):在高并发场景下,边缘触发模式具有更高的性能,但要求程序确保数据一次性读取完毕,代码实现较复杂。适用于高性能服务器的设计,比如 Nginx 和 Redis 服务器。

总结来说,水平触发模式适合简单易用的场景边缘触发模式则适用于追求性能的高并发系统。在实际开发中,选择触发模式时应综合考虑系统的并发量、对性能的要求以及代码的复杂度。


5. Go 实现一个简单的聊天室服务器

5.1 实现思路

聊天室服务器的核心功能是管理多个客户端的连接,并支持消息广播。具体而言,这个服务器需要具备以下功能:

  1. 监听客户端连接:通过 epoll 监听客户端的连接请求,并将连接加入 epoll 实例的监听列表中。
  2. 处理客户端消息:在收到某个客户端的消息时,服务器将消息广播给其他所有客户端。
  3. 边缘触发模式下的高效读写:在边缘触发(ET)模式下实现非阻塞读写,保证在一次触发中尽量将数据处理完。

5.2 使用 epoll 管理客户端连接

在实现中,我们将使用 Go 的 syscall 包直接调用 epoll 系统接口。每个新连接或就绪的客户端 socket 会通过 epoll_wait 触发事件,从而被服务器捕获并处理。边缘触发模式要求我们在处理每个 socket 时确保数据被一次性读取完毕,避免遗漏数据。

5.3 代码实现

以下是完整的聊天室服务器代码,实现了客户端连接管理、消息广播和边缘触发模式的高效事件处理。代码详细注释了各个步骤,便于理解 epoll 的具体应用。

package mainimport ("fmt""net""syscall"
)const (MaxEvents = 10
)func main() {// 1. 创建监听 socketlistener, err := net.Listen("tcp", ":8080")if err != nil {panic(err)}defer listener.Close()fmt.Println("Chat server started on :8080")// 2. 创建 epoll 实例epollFD, err := syscall.EpollCreate1(0)if err != nil {panic(err)}defer syscall.Close(epollFD)// 3. 将监听 socket 的文件描述符加入 epoll 实例listenerFD := int(listener.(*net.TCPListener).Fd())addToEpoll(epollFD, listenerFD, syscall.EPOLLIN)// 创建事件列表和客户端连接映射events := make([]syscall.EpollEvent, MaxEvents)clients := make(map[int]net.Conn) // 存储客户端连接,键为文件描述符for {// 4. 等待事件触发n, err := syscall.EpollWait(epollFD, events, -1)if err != nil {panic(err)}// 5. 遍历每个就绪事件for i := 0; i < n; i++ {fd := int(events[i].Fd)if fd == listenerFD {// 处理新的客户端连接conn, err := listener.Accept()if err != nil {fmt.Println("Error accepting connection:", err)continue}clientFD := int(conn.(*net.TCPConn).Fd())addToEpoll(epollFD, clientFD, syscall.EPOLLIN|syscall.EPOLLET) // 使用边缘触发clients[clientFD] = connfmt.Println("New client connected:", clientFD)} else {// 处理来自客户端的数据handleClientMessage(fd, epollFD, clients)}}}
}// addToEpoll 将文件描述符添加到 epoll 实例中,监听指定事件
func addToEpoll(epollFD int, fd int, events uint32) {event := syscall.EpollEvent{Events: events, Fd: int32(fd)}if err := syscall.EpollCtl(epollFD, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {panic(err)}
}// handleClientMessage 读取客户端消息并广播给其他客户端
func handleClientMessage(clientFD int, epollFD int, clients map[int]net.Conn) {buf := make([]byte, 512)conn := clients[clientFD]// 使用边缘触发,循环读取数据直到读取完毕for {n, err := conn.Read(buf)if n == 0 || err != nil {// 客户端断开连接fmt.Printf("Client %d disconnected\n", clientFD)syscall.EpollCtl(epollFD, syscall.EPOLL_CTL_DEL, clientFD, nil)conn.Close()delete(clients, clientFD)break}// 打印并广播消息message := fmt.Sprintf("Client %d: %s", clientFD, string(buf[:n]))fmt.Print(message)broadcastMessage(clientFD, message, clients)}
}// broadcastMessage 将消息广播给其他所有客户端
func broadcastMessage(senderFD int, message string, clients map[int]net.Conn) {for fd, conn := range clients {if fd != senderFD { // 不发送给自己conn.Write([]byte(message))}}
}

5.4 代码解析

  1. 创建监听 socket:使用 net.Listen 启动一个 TCP 监听 socket 以接受客户端连接。
  2. 创建 epoll 实例:通过 syscall.EpollCreate1 创建一个 epoll 实例,返回 epollFD 文件描述符,用于管理多个客户端连接。
  3. 将监听 socket 添加到 epoll 实例:将监听 socket 的文件描述符添加到 epoll,并设置监听 EPOLLIN 事件,表示有新的客户端连接时会触发事件。
  4. 等待事件触发syscall.EpollWait 阻塞等待事件触发,并返回已经就绪的事件列表。
  5. 处理新客户端连接:当监听 socket 的事件触发时,表示有新客户端连接。使用 Accept 接受连接,并将新连接的文件描述符添加到 epoll 中,设置为 EPOLLET 模式(边缘触发)。
  6. 读取客户端消息并广播:当客户端 socket 的事件触发时,表示有消息可读。在 handleClientMessage 中,我们使用非阻塞方式循环读取数据,直到所有数据读取完毕,随后广播消息给其他客户端。
  7. 广播消息broadcastMessage 函数将来自某个客户端的消息广播给所有其他客户端,实现聊天室功能。

5.5 边缘触发的关键点

在边缘触发模式(EPOLLET)下,epoll_wait 只会在文件描述符状态发生变化时触发一次。为确保在一次触发中处理完所有数据,我们在 handleClientMessage 函数中使用非阻塞读取,循环读取直到所有数据读完。这避免了数据遗漏,同时利用边缘触发的高性能。


5.6 流程图:事件处理流程

以下流程图展示了聊天室服务器的事件处理流程,帮助我们直观理解每一步骤:
完成触发流程


6. 总结

在本篇文章中,我们系统深入地讲解了 IO 多路复用技术,从基础概念到具体实现,帮助读者理解其在高并发网络编程中的重要性。以下是我们文章中的关键要点总结:

  1. IO 多路复用的意义与应用场景:我们首先介绍了 IO 多路复用的重要性。通过允许单线程管理多个 IO 通道,IO 多路复用可以极大地提升服务器的并发能力,广泛应用于高性能服务器、实时通讯系统和数据库服务等场景。

  2. 三种 IO 多路复用实现方式:selectpollepoll:我们分别介绍了 selectpollepoll 的基本原理、优缺点以及适用场景。虽然 selectpoll 提供了基本的 IO 多路复用功能,但它们的性能在高并发下存在瓶颈。epoll 则是专为高并发设计的高效 IO 多路复用机制,具备 O(1) 的性能特征,是大型 Linux 服务器应用的主流选择。

  3. 深入理解 epoll 的实现细节:通过讲解 epoll 的三大操作(epoll_createepoll_ctlepoll_wait)、核心数据结构(红黑树和就绪链表)、以及事件触发模式(边缘触发和水平触发),我们详细剖析了 epoll 的高效实现原理。特别是边缘触发模式下的非阻塞处理,帮助我们了解了如何在高并发场景下充分利用 epoll 的性能优势。

  4. 基于 Go 实现的聊天室服务器示例:我们提供了一个简单的聊天室服务器实现,展示了 epoll 的实际应用。通过 epoll 的边缘触发模式,服务器能够高效管理多个客户端连接并进行消息广播。具体代码实现帮助我们理解如何使用 epoll 的非阻塞读写来确保数据处理的完整性。


结束语

IO 多路复用是一项强大的技术,epoll 的高效实现为 Linux 系统中的高并发网络编程提供了有力支持。在本篇文章中,我们通过详细讲解和示例实现,让大家更加深入地理解了 IO 多路复用技术的原理和应用。

祝大家在 IO 多路复用和高并发编程的学习之旅中一帆风顺!如有任何问题或讨论,欢迎留言,我们共同交流。


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

大学英语神器:让GPT帮助你攻克完型填空和阅读理解

这里写目录标题 0、前言一、再来十篇完型填空和阅读理解第一部分&#xff1a;操作指南1.访问链接&#xff1a;ChatGPT 4o国内直接访问地址&#xff1a;https://share.xuzhugpt.cloud/2.上plus的车 第二部分&#xff1a;实操展示①完型填空②阅读理解 二、用户体验 0、前言 学习…

masm汇编debug调试1~100求和

计算123...100并把结果放到寄存器AX里 assume cs:codecode segment start:mov ax,0mov cx,100 s:add ax,cxloop smov ax,4c00hint 21hcode ends end start 效果演示&#xff1a;

LeetCode3226题. 使两个整数相等的位更改次数(原创)

【题目描述】 给你两个正整数 n 和 k。 你可以选择 n 的 二进制表示 中任意一个值为 1 的位&#xff0c;并将其改为 0。 返回使得 n 等于 k 所需要的更改次数。如果无法实现&#xff0c;返回 -1。 示例 1&#xff1a; 输入&#xff1a; n 13, k 4 输出&#xff1a; 2 解释&am…

ubuntu 异常 断电 日志 查看

sudo less /var/log/syslog 搜 Linux version

Python:入门基础

目录 常量和表达式 变量 变量的语法 变量的类型 动态类型特性 注释的使用 输入和输出 通过控制台输出 通过控制台输入 运算符 算术运算符 关系运算符 逻辑运算符 赋值运算符 常量和表达式 print是Python中的一个内置函数&#xff0c;使用print函数可以将数据打印…

ChatGPT 高级语音模式已登陆 Windows 和 Mac 平台,对话更自然

OpenAI ChatGPT 高级语音模式已登陆 Windows 和 Mac 平台&#xff0c;对话更自然&#xff0c;拟态更逼真 OpenAI 于10月31日正式宣布&#xff0c;ChatGPT 的高级语音模式&#xff08;Advanced Voice Mode&#xff0c;简称 AVM&#xff09;现已登陆 Windows 和 Mac 平台。基于最…

【深度学习】InstantIR:图片高清化修复

InstantIR——借助即时生成参考的盲图像修复新方法 作者:Jen-Yuan Huang 等 近年来,随着深度学习和计算机视觉技术的飞速发展,图像修复技术取得了令人瞩目的进步。然而,对于未知或复杂退化的图像进行修复,仍然是一个充满挑战的任务。针对这一难题,研究者们提出了 Insta…

【深度学习】实验 — 动手实现 GPT【三】:LLM架构、LayerNorm、GELU激活函数

【深度学习】实验 — 动手实现 GPT【三】&#xff1a;LLM架构、LayerNorm、GELU激活函数 模型定义编码一个大型语言模型&#xff08;LLM&#xff09;架构 使用层归一化对激活值进行归一化LayerNorm代码实现scale和shift 实现带有 GELU 激活的前馈网络测试 模型定义 编码一个大…

信息抽取与知识图谱技术在医疗领域中的应用

​快瞳AI开放平台支持多种输入格式&#xff0c;如电子病历、临床数据和医学文献等&#xff0c;可以将这些信息快速转换为结构化数据&#xff0c;包括自动360度不同角度的旋转识别、自动校准弯曲透视、光照不均、手写叠加处理等&#xff0c;提升数据的可操作性和可检索性。通过我…

SpringCloudAlibaba实战入门之OpenFeign高级用法(十)

在上一篇中我们简单了解了OpenFeign的简单使用,本篇是承接上一篇的高级使用拓展内容。 一、@FeignClient 标签的常用属性 @FeignClient 注解是 Spring Cloud OpenFeign 中用于声明一个 Feign 客户端的核心注解。它可以用来指定服务的名称、配置类、负载均衡策略等。下面是 @…

DBeaver 数据库安装及破解个人使用 不同版本不同jdk

DBeaver DBeaver 分为 **Lite、Enterprise、Ultimate&#xff08;功能最全&#xff09;、Community&#xff0c;**其中Community免费使用&#xff0c;但是功能不言而喻&#xff0c;具体差异自行去官网对比。 安装 DBeaver 到官网下载即可 https://dbeaver.io/download/ 激活 D…

docker安装中的遇到的问题及解决方案

docker 安装中遇到的问题及解决方案 截至2024/11/1&#xff0c;我在安装docker中遇到的问题将悉数列出&#xff0c;供大家参考。 说明&#xff1a;这些解决方案在我自己的虚拟机中有用&#xff0c;可能大家的虚拟机并不适用&#xff0c;这些解决方案均转载自另外的博客&#x…

Jetson OrinNX平台CSI相机导致cpu load average升高问题调试

1. 前言 硬件: Orin NX JP: 5.1.2, R35.4.1 用v4l2-ctl --stream-mmap -d0 命令去获取相机数据时, 用top查看cpu使用情况, CPU占用率很低,但load average在1左右, 无任何程序运行时,load average 为0 用ps -aux 查看当前进程情况,发现有两个系统进程vi-output, …

AppInventor2能否用网络摄像头画面作为屏幕的背景?

// 视频是否可以作为背景&#xff1f; // 有会员提问&#xff1a;能否用网络摄像头的实时画面作为屏幕的背景&#xff1f;就跟这个一样背景全覆盖&#xff1a; 摄像头画面是一个在线的网站链接视频流。 // 原先思路 // 1、目前原生组件无法直接实现这个功能&#xff0c;屏幕…

【开源免费】基于SpringBoot+Vue.JS网上租赁系统(JAVA毕业设计)

本文项目编号 T 050 &#xff0c;文末自助获取源码 \color{red}{T050&#xff0c;文末自助获取源码} T050&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计5.4.1 用…

fmql之Linux以太网

正点原子第57章。 dts fmql-dtsi&#xff1a; 我们用的PHY芯片是RTL8211F&#xff1a; 需要添加PHY信息&#xff1a; fmql-dtsi提供的参考&#xff1a; 根据vivado工程自动生成的&#xff1a; reg <0x1>; 配置 疑问 网口通讯需要网线&#xff0c;但是目前板卡上只有PS…

基于STM32的农业监测与管理系统设计思路介绍(代码示例)

一、项目概述 在全球农业现代化进程中&#xff0c;农业监测与管理系统的研发具有重要意义。本文介绍的基于STM32的农业监测与管理系统&#xff0c;旨在通过智能小车实现对农作物的环境监测、土壤检测等功能。该系统利用手势控制技术&#xff0c;农民可以通过简单的手势指令来操…

【2024-10-31-2024-11-03】LeetCode刷题——python语法基础题

&#x1f4dd;前言说明&#xff1a; ●本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;主要跟随B站作者灵茶山的视频进行学习&#xff0c;专栏中一篇文章为B站对应的一个视频 题目主要为B站视频内涉及的题目以及B站视频中提到的“课后作业”。 ●文章中的理…

2024年【烟花爆竹储存】考试试卷及烟花爆竹储存试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 烟花爆竹储存考试试卷考前必练&#xff01;安全生产模拟考试一点通每个月更新烟花爆竹储存试题及解析题目及答案&#xff01;多做几遍&#xff0c;其实通过烟花爆竹储存作业模拟考试很简单。 1、【单选题】( )负责烟花…

Uniapp的H5以及App不支持后端传FormData类型参数的解决方案

在uniapp中不支持FormData的传参&#xff0c;这就很恶心&#xff1b;如果强行传的话会提示&#xff0c;请求失败的报错信息。 因为后端必须要FormData类型的传参&#xff0c;所以在查阅一系列方案后&#xff0c;有一种解决办法可以完美解决。 代码&#xff1a; init() {const…