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

高性能编程:无锁队列

目录

1. 无锁队列

1.1 无锁

1.1.1 阻塞(Blocking)

1.1.2 无锁(Lock-Free)

1.1.3 无等待(Wait-Free)

1.2 队列

1.2.1 链表实现的队列

1.2.2 数组实现的队列

1.2.3 混合实现的队列

1.3 多线程中的先进先出数据结构

1.4 影响队列性能的因素

2. 为什么需要无锁队列

2.1 多线程环境的开销

2.1.1 线程切换和上下文切换

2.1.2 缓存损坏(Cache Pollution)

2.1.3 时间浪费在保护队列时的争夺上

2.2 不能使用基于锁的情况

2.2.1 信号处理程序(中断处理)

2.2.2 硬实时系统(执行时间有限)

3. 无锁队列的分类

3.1 MPMC(Multiple Producers Multiple Consumers)

3.2 SPSC(Single Producer Single Consumer)

3.3 MPSC(Multiple Producers Single Consumer)

3.4 SPMC(Single Producer Multiple Consumers)

4. 设计队列的原则 

4.1 根据任务的耗时设计生产者和消费者的数量

4.2 根据生产者和消费者的数量设计队列类型

4.3总结 

5. LockedQueue:队列为空时不阻塞消费者线程

5.1 为什么选择基于锁的队列

5.2 LockedQueue 的设计原则


1. 无锁队列

无锁队列是一种在多线程环境下,不使用传统锁机制(如互斥锁、信号量)即可实现线程安全的先进先出(FIFO)数据结构。它主要依赖于原子操作内存屏障来保证并发操作的正确性和数据一致性。

1.1 无锁

无锁(Lock-Free)是并发编程中的一种非阻塞同步方式,旨在提高系统的并发性能,避免锁竞争导致的性能瓶颈。

1.1.1 阻塞(Blocking)
  • 定义:阻塞是指线程在无法获取所需资源时,会进入等待状态,直到资源可用。较弱的保证系统向前移动。(比如:自旋锁)
  • 缺点
    • 线程挂起:导致线程被挂起,增加了上下文切换的开销。
    • 死锁风险:多个线程互相等待对方释放资源,可能导致死锁。
    • 锁竞争:高并发环境下,锁的竞争会严重影响系统性能。
1.1.2 无锁(Lock-Free)
  • 定义:无锁算法保证至少有一个线程在有限的步骤内完成操作,即系统整体是前进的。较强保证系统向前移动。(比如:cas,允许有限循环)
  • 特点
    • 非阻塞:线程不会因为获取不到锁而阻塞。
    • 高并发性:减少了锁竞争,提高了系统的吞吐量。
    • 活跃性:即使某个线程挂起,其他线程仍能继续执行。
  • 实现手段
    • 原子操作:使用硬件提供的原子指令,如CAS(Compare-And-Swap)等。
    • 内存屏障:确保指令执行的顺序和内存的可见性,防止编译器或CPU重排序导致的问题。
1.1.3 无等待(Wait-Free)
  • 定义:无等待算法保证所有线程都能在有限的步骤内完成操作,即不存在饥饿或活锁的情况。强保证系统向前移动。(比如:exchange、fetch_add)
  • 特点
    • 最强的非阻塞属性:确保每个操作都能在有限的时间内完成。
    • 实现复杂:需要精心设计算法,通常实现难度较高。
  • 实现手段
    • 仅使用原子操作和内存屏障:完全依赖硬件支持,避免任何形式的阻塞。
1.2 队列

队列是一种先进先出(FIFO)的数据结构,广泛应用于多线程环境下的任务调度、消息传递等。

1.2.1 链表实现的队列
  • 优点
    • 动态扩展:不受固定容量限制,可根据需要动态增加节点。
    • 内存利用率高:只分配实际需要的内存,没有空间浪费。
  • 缺点
    • 频繁的内存分配和释放:每次入队和出队都需要在堆上进行内存操作,增加了系统开销。
    • 缓存局部性差:链表节点在内存中不连续,导致CPU缓存命中率低,影响性能。
1.2.2 数组实现的队列
  • 优点
    • 高缓存命中率:数组元素在内存中连续存储,缓存友好性高。
    • 访问速度快:通过索引快速访问元素,效率高。
  • 缺点
    • 容量固定:需要预先设定数组大小,可能会出现容量不足或内存浪费的情况。
    • 扩容成本高:如果需要扩容,可能需要搬移数据,影响性能。
1.2.3 混合实现的队列
  • 概念:结合链表和数组的优点,设计一种既能动态扩展又具有高性能的队列。
  • 实现方式
    • 分段队列:将队列划分为多个数组段,每个段用数组实现,段与段之间用链表连接。
    • 环形缓冲区(Ring Buffer):使用数组实现的循环队列,利用取模操作实现队列的循环特性。
1.3 多线程中的先进先出数据结构

在多线程环境下,实现线程安全的FIFO结构,需要解决并发访问和数据一致性的问题。

  • 挑战

    • 数据竞争:多个线程同时访问或修改共享数据,可能导致数据不一致。
    • 原子性:需要确保入队和出队操作的原子性,防止部分更新导致的数据错误。
    • 内存可见性:一个线程的修改需要及时对其他线程可见。
  • 解决方案

    • 原子操作:使用CAS等原子指令,确保对共享变量的更新是不可分割的。
    • 内存屏障:防止指令重排序,确保内存访问的顺序性和可见性。
    • ABA问题处理:使用版本号或指针标记,避免CAS操作中的ABA问题。
1.4 影响队列性能的因素
  • 频繁在堆上分配空间

    • 问题:链表实现的队列需要频繁地分配和释放节点,增加了内存管理的开销。
    • 影响
      • 内存碎片化:频繁的内存操作可能导致内存碎片,降低内存利用率。
      • 性能下降:内存分配和释放操作耗时,影响队列的性能。
    • 解决方案
      • 使用内存池:预先分配一块连续的内存空间,重复利用节点,减少内存分配和释放的次数。
      • 对象池技术:将释放的节点放入对象池,供后续复用,降低内存管理的开销。
  • 缓存局部性

    • 问题:链表节点不连续存储,导致缓存命中率低。
    • 影响
      • 缓存未命中:CPU需要从主存读取数据,延迟高。
    • 解决方案
      • 使用数组或环形缓冲区:提高数据的连续性,增加缓存命中率。
  • False Sharing(伪共享)

    • 问题:多个线程修改位于同一缓存行的不同变量,导致缓存一致性协议频繁生效。
    • 影响
      • 性能下降:缓存行被频繁失效,增加了内存子系统的负担。
    • 解决方案
      • 缓存行填充:在变量之间插入填充数据,使得每个变量占据独立的缓存行,避免伪共享。
  • 原子操作的开销

    • 问题:原子操作通常比普通的内存访问要慢,过多的原子操作会影响性能。
    • 影响
      • 吞吐量下降:原子操作需要锁总线或使用内存屏障,增加了指令执行的延迟。
    • 解决方案
      • 减少原子操作次数:优化算法,尽可能减少对共享变量的原子操作。
      • 局部化变量:将共享变量的访问范围缩小,降低并发冲突。

2. 为什么需要无锁队列

在多线程和并发编程中,无锁队列的引入是为了克服传统锁机制带来的性能瓶颈和局限性。以下是需要无锁队列的主要原因:

2.1 多线程环境的开销

在多线程环境下,使用锁来保护共享资源会引入额外的系统开销,这些开销可能会显著影响程序的性能和响应性。

2.1.1 线程切换和上下文切换
  • 线程切换:当线程试图获取已经被其他线程持有的锁时,可能会被阻塞,操作系统会将其从运行队列中移除,调度其他线程。这种线程切换会增加调度器的负担。
  • 上下文切换:线程切换需要保存当前线程的执行上下文(如寄存器状态、程序计数器等),并加载新线程的上下文。这一过程消耗了CPU时间和资源。
  • 影响:频繁的线程和上下文切换会导致系统性能下降,增加了线程调度的延迟。
2.1.2 缓存损坏(Cache Pollution)
  • 缓存一致性协议的开销:当多个线程竞争同一把锁时,会导致CPU缓存中的锁变量频繁失效,触发缓存一致性协议,增加了内存子系统的负担。
  • 缓存行争用:锁变量可能与其他数据位于同一缓存行中,导致伪共享(False Sharing),进一步降低缓存性能。
  • 影响:缓存命中率降低,内存访问延迟增加,整体性能受到影响。
2.1.3 时间浪费在保护队列时的争夺上
  • 锁竞争:线程在获取锁的过程中,会消耗时间等待其他线程释放锁,这些时间本可以用于执行实际任务。
  • 资源浪费:CPU周期被浪费在锁的获取和释放上,而不是用于有意义的计算。
  • 性能瓶颈:在高并发环境下,锁的争夺会成为系统的主要性能瓶颈,限制了并发度。

总结:无锁队列通过使用原子操作避免了锁的使用,减少了线程和上下文切换,降低了缓存一致性协议的开销,使线程能够将更多的时间用于执行实际任务,提高了系统的整体性能。

2.2 不能使用基于锁的情况

在某些特殊的编程环境或应用场景中,传统的锁机制并不适用,此时需要使用无锁的同步方式。

2.2.1 信号处理程序(中断处理)
  • 中断上下文:信号处理程序可能在任何时候被触发,包括在一个线程持有锁的情况下。
  • 不可重入性:如果信号处理程序尝试获取同一把锁,可能导致死锁或未定义行为,因为锁可能不可重入。
  • 执行限制:信号处理程序应尽可能快地执行完毕,不能阻塞或等待资源。
  • 解决方案:使用无锁队列,使信号处理程序能够安全、快速地将数据入队或出队,而无需获取锁。
2.2.2 硬实时系统(执行时间有限)
  • 实时性要求:硬实时系统对任务的执行时间有严格的限制,任何延迟都可能导致系统故障。
  • 不可预测的延迟:锁机制可能导致不可预测的阻塞时间,无法满足实时性的要求。
  • 死锁风险:在实时系统中,死锁是不可接受的,因为它可能导致关键任务无法完成。
  • 确定性:无锁算法具有更好的时间确定性,操作的执行时间是有限且可预测的。
  • 解决方案:采用无等待(Wait-Free)或无锁(Lock-Free)算法,确保所有操作都能在有限的步骤内完成,满足实时系统的严格要求。

3. 无锁队列的分类

无锁队列根据生产者(Producer)和消费者(Consumer)的数量不同,可以分为以下几类:

  1. MPMC(Multiple Producers Multiple Consumers):多生产者多消费者
  2. SPSC(Single Producer Single Consumer):单生产者单消费者
  3. MPSC(Multiple Producers Single Consumer):多生产者单消费者
  4. SPMC(Single Producer Multiple Consumers):单生产者多消费者
3.1 MPMC(Multiple Producers Multiple Consumers)

定义:MPMC队列允许多个生产者线程同时入队,多个消费者线程同时出队。

特点

  • 高度并发:支持多个生产者和消费者同时操作,适用于高并发场景。
  • 复杂性高:由于需要处理多个生产者和消费者的并发访问,算法设计更为复杂,确保线程安全性和无锁性更具挑战。
  • 性能开销较大:相比其他类型的队列,MPMC队列通常需要更多的同步机制来处理并发操作,可能导致更高的CPU开销。

应用场景

  • 任务调度系统:多个任务生成者和多个任务处理者。
  • 消息传递系统:多个消息发送者和多个消息接收者。
  • 高性能服务器:处理大量并发请求的场景。

实现示例

  • Michael & Scott队列:一种经典的基于链表的MPMC无锁队列,使用CAS操作来管理头尾指针。
  • Boost.Lockfree库中的MPMC队列:C++中常用的高性能无锁队列实现。

优缺点

  • 优点
    • 高度并发,适应复杂的多线程环境。
    • 灵活性强,适用于多种应用场景。
  • 缺点
    • 实现复杂,容易出错。
    • 相较于其他类型,性能开销更大。
3.2 SPSC(Single Producer Single Consumer)

定义:SPSC队列仅允许一个生产者线程进行入队操作,一个消费者线程进行出队操作。

特点

  • 简单高效:由于只有单一的生产者和消费者,不需要复杂的同步机制,算法实现相对简单。
  • 高性能:低开销,通常比MPMC、MPSC和SPMC队列更快,因为无需处理多线程竞争。
  • 缓存友好:由于生产者和消费者的操作不重叠,缓存行冲突较少,性能更佳。

应用场景

  • 单线程生产与消费:如一个线程生成任务,另一个线程处理任务。
  • 嵌入式系统:资源受限的系统中,单生产者单消费者模型简单高效。
  • 音视频处理:如一个线程捕获音视频数据,另一个线程进行编码或播放。

实现示例

  • 环形缓冲区(Ring Buffer):常用于SPSC队列,利用固定大小的数组和头尾指针实现高效的FIFO操作。
  • Boost.Lockfree库中的SPSC队列:提供了简洁高效的无锁SPSC队列实现。

优缺点

  • 优点
    • 实现简单,容易理解和维护。
    • 性能极高,适用于高吞吐量的应用场景。
  • 缺点
    • 仅适用于单生产者单消费者的场景,灵活性较低。
3.3 MPSC(Multiple Producers Single Consumer)

定义:MPSC队列允许多个生产者线程同时入队,但仅有一个消费者线程进行出队操作。

特点

  • 适度并发:支持多个生产者同时入队,适合有多个任务生成者但只有单一任务处理者的场景。
  • 实现中等复杂度:相比SPSC,MPSC需要处理多个生产者的并发入队操作,但只需确保单一消费者的安全出队。
  • 性能适中:由于只有单一消费者,出队操作相对简单,但入队操作仍需处理多线程竞争。

应用场景

  • 日志系统:多个线程生成日志消息,单一线程负责写入日志文件。
  • 事件处理系统:多个事件源生成事件,单一事件处理器进行处理。
  • 任务队列:多个任务生成器,单一任务调度器执行任务。

实现示例

  • Lamport队列:一种经典的MPSC无锁队列,实现多个生产者入队和单一消费者出队。
  • Boost.Lockfree库中的MPSC队列:提供了支持多生产者的高效无锁队列实现。

优缺点

  • 优点
    • 支持多生产者,提高任务生成的并发性。
    • 实现相对简单,适合单消费者场景。
  • 缺点
    • 仅适用于单一消费者,灵活性有限。
    • 多生产者的并发入队可能带来一定的性能开销。
3.4 SPMC(Single Producer Multiple Consumers)

定义:SPMC队列允许一个生产者线程进行入队操作,多个消费者线程同时进行出队操作。

特点

  • 适度并发:支持多个消费者同时出队,适合有单一任务生成者但多个任务处理者的场景。
  • 实现复杂度中等:需要确保多个消费者安全地进行出队操作,避免数据竞争和重复消费。
  • 性能适中:入队操作简单,只需单一生产者,但出队操作需要处理多消费者的并发访问。

应用场景

  • 工作池:单一任务生成者,多个工作线程并行处理任务。
  • 消息广播系统:单一消息源,多个消费者接收和处理消息。
  • 数据流处理:单一数据生产者,多个处理器并行处理数据流。

实现示例

  • 分布式队列:如Kafka的部分实现,支持单一生产者和多个消费者。
  • 自定义SPMC无锁队列:需要特别设计以确保多个消费者的安全出队。

优缺点

  • 优点
    • 支持多个消费者,提高任务处理的并行度。
    • 适合需要并行处理任务的场景。
  • 缺点
    • 实现复杂度较高,需要处理多个消费者的出队竞争。
    • 可能存在出队操作的性能瓶颈。

4. 设计队列的原则 

4.1 根据任务的耗时设计生产者和消费者的数量

原则说明

任务的耗时对生产者和消费者的数量配置有直接影响。任务耗时长短不一时,需要合理安排生产者和消费者的比例,以确保队列的高效运行,避免生产者或消费者成为系统的瓶颈。

具体指导

  • 任务耗时较长

    • 增加消费者数量:如果每个任务的执行时间较长,消费者处理任务的速度较慢,此时可以通过增加消费者的数量来提高处理能力,减少任务在队列中的积压。

    • 平衡系统资源:确保增加的消费者不会导致系统资源(如CPU、内存)过载。根据任务的具体需求,合理分配消费者数量,以实现最佳的处理效率。

  • 任务耗时较短

    • 适当减少消费者数量:对于耗时较短的任务,单个消费者可以快速处理多个任务。因此,不需要过多的消费者来处理任务,避免资源的浪费。

    • 优化生产者数量:确保生产者能够以较高的速度生成任务,消费者能够及时处理,维持队列的平衡状态。

示例

  • 长耗时任务场景

    • 应用场景:视频渲染、大规模数据处理、复杂计算任务。

    • 设计策略:假设每个任务平均耗时10秒,生产者生成任务的速度较快(每秒生成多个任务),此时可以配置多个消费者(例如,4-8个消费者)来并行处理任务,确保队列中的任务不会迅速积压。

  • 短耗时任务场景

    • 应用场景:日志记录、简单的数据传输、轻量级的事件处理。

    • 设计策略:假设每个任务平均耗时10毫秒,消费者处理速度较快,可以配置较少的消费者(例如,1-2个消费者)即可满足需求,同时避免过多的消费者导致资源浪费。

4.2 根据生产者和消费者的数量设计队列类型

原则说明

不同的生产者和消费者数量组合(如SPSC、MPSC、SPMC、MPMC)对队列的选择和设计有不同的要求。根据实际的生产者和消费者数量,选择合适的无锁队列类型,可以最大化性能并简化实现复杂度。

具体指导

  • 单生产者单消费者(SPSC)

    • 特点:实现简单,性能最高。

    • 适用场景:任务生成和处理严格是一对一关系,且没有其他并发需求。

    • 设计策略:选择SPSC无锁队列,如环形缓冲区(Ring Buffer),以实现最高效的FIFO操作。

  • 多生产者单消费者(MPSC)

    • 特点:支持多个生产者同时入队,单一消费者出队。

    • 适用场景:多个线程生成任务,单一线程处理任务,如日志系统、事件处理器。

    • 设计策略:选择MPSC无锁队列,确保入队操作的线程安全,同时简化消费者的出队逻辑。

  • 单生产者多消费者(SPMC)

    • 特点:单一生产者入队,多个消费者同时出队。

    • 适用场景:单一任务生成源,多线程并行处理任务,如工作池、并行数据处理。

    • 设计策略:选择SPMC无锁队列,确保多个消费者能够安全地从队列中出队,避免任务重复处理。

  • 多生产者多消费者(MPMC)

    • 特点:支持多个生产者和多个消费者同时操作。

    • 适用场景:高并发环境,多个任务生成源和处理者,如高性能服务器、分布式系统中的任务调度。

    • 设计策略:选择MPMC无锁队列,如Michael & Scott队列,确保在高度并发下的线程安全和高吞吐量。

示例

  • 日志系统

    • 生产者与消费者:多个应用线程生成日志(多生产者),单一日志写入线程(单消费者)。

    • 队列类型:选择MPSC无锁队列,支持多线程并发入队,确保日志的有序写入。

  • 工作池

    • 生产者与消费者:单一任务生成线程(单生产者),多个工作线程(多消费者)并行处理任务。

    • 队列类型:选择SPMC无锁队列,允许多个消费者安全地从队列中获取任务。

4.3总结 

在设计无锁队列时,考虑任务的耗时生产者与消费者的数量是两个关键原则:

  1. 任务的耗时

    • 长耗时任务:增加消费者数量,以提高处理能力,减少队列积压。
    • 短耗时任务:适当减少消费者数量,避免资源浪费,同时保持高效的任务处理。
  2. 生产者与消费者的数量

    • 根据生产者和消费者的具体数量选择合适的队列类型(SPSC、MPSC、SPMC、MPMC),以优化性能和简化实现复杂度。

5. LockedQueue:队列为空时不阻塞消费者线程

LockedQueue是一种基于锁的队列实现,当队列为空时,消费者线程不会被阻塞。它适用于任务耗时长短不一且不需要严格区分生产者和消费者数量的场景。这种设计允许消费者在队列为空时继续执行其他任务或进行轮询,而不是被迫等待新任务的到来。

5.1 为什么选择基于锁的队列

尽管无锁队列在高并发场景下具有显著的性能优势,但基于锁的队列在某些情况下仍然具有以下优势:

  1. 实现简单:基于锁的队列实现相对直观,易于理解和维护。
  2. 适用性广:适用于生产者和消费者数量不固定,且任务处理时间不一致的场景。
  3. 低并发需求:在并发程度不高的应用中,基于锁的开销较低,且不会成为性能瓶颈。
5.2 LockedQueue 的设计原则

根据您提供的设计原则,LockedQueue主要考虑以下两点:

  1. 任务的耗时:任务执行时间不一,可能有长有短。
  2. 生产者和消费者的数量:不区分生产者和消费者的具体数量。

这种设计允许队列在处理任务时更加灵活,消费者线程在队列为空时不会被阻塞,可以进行其他操作或继续轮询,提高了系统的响应性和资源利用率。

相关文章:

高性能编程:无锁队列

目录 1. 无锁队列 1.1 无锁 1.1.1 阻塞(Blocking) 1.1.2 无锁(Lock-Free) 1.1.3 无等待(Wait-Free) 1.2 队列 1.2.1 链表实现的队列 1.2.2 数组实现的队列 1.2.3 混合实现的队列 1.3 多线程中的先…...

word标题排序编号错误

1.问题:word中有时会出现当前编号是2.1、3.1、4.1,下级编号却从1.1.1开始的情况,类似情况如下: 2.原因:此问题多为编号4.1、4.2和编号4.1.1使用的多级编号模板不一样,可以选中4.2,看下使用的多级…...

力扣---80. 删除有序数组中的重复项 II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 说明&…...

一篇文章,讲清SQL的 joins 语法

SQL 中的不同 JOIN 类型: 1. (INNER)JOIN(内连接):返回两个表中具有匹配值的记录。 2. LEFT(OUTER)JOIN(左外连接):返回左表中的所有记录&#…...

设计模式之建造者模式(通俗易懂--代码辅助理解【Java版】)

文章目录 设计模式概述1、建造者模式2、建造者模式使用场景3、优点4、缺点5、主要角色6、代码示例:1)实现要求2)UML图3)实现步骤:1)创建一个表示食物条目和食物包装的接口2)创建实现Packing接口的实体类3&a…...

文生视频算法

文生视频 Sora解决问题:解决思路: CogVideoX解决问题:解决思路: Stable Video Diffusion(SVD)解决问题:解决思路: 主流AI视频技术框架: Sora Sora: A Review on Backg…...

LoRA: Low-Rank Adaptation Abstract

LoRA: Low-Rank Adaptation Abstract LoRA 论文的摘要介绍了一种用于减少大规模预训练模型微调过程中可训练参数数量和内存需求的方法,例如拥有1750亿参数的GPT-3。LoRA 通过冻结模型权重并引入可训练的低秩分解矩阵,减少了10,000倍的可训练参数&#xf…...

正点原子阿尔法ARM开发板-IMX6ULL(二)——介绍情况以及汇编

文章目录 一、裸机开发(21个)二、嵌入式Linux驱动例程三、汇编3.1 处理器内部数据传输指令3.2 存储器访问指令3.3 压栈和出栈指令3.4 跳转指令3.5 算术运算指令3.6 逻辑运算指令 一、裸机开发(21个) 二、嵌入式Linux驱动例程 三、…...

Unreal Engine——AI生成高精度的虚拟人物和环境(虚拟世界构建、电影场景生成)(一)

一、Unreal Engine 介绍 Unreal Engine(虚幻引擎)是由Epic Games开发的强大3D游戏开发引擎,自1998年首次发布以来,已经历了多个版本的迭代。虚幻引擎主要用于制作高品质的3D游戏,但也广泛用于电影、建筑、仿真等其他领…...

Emlog程序屏蔽用户IP拉黑名单插件

插件介绍 在很多时候我们需要得到用户的真实IP地址,例如,日志记录,地理定位,将用户信息,网站数据分析等,其实获取IP地址很简单,感兴趣的可以参考一下。 今天给大家带来舍力写的emlog插件:屏蔽…...

发送成绩的app或小程序推荐

老师们,新学期的第一次月考马上开始,是不是还在为如何高效、便捷地发布成绩而头疼呢?别担心,都2024年了,我们有更智能的方式来解决这个问题! 给大家安利一个超级实用的工具——易查分小程序。这个小程序简…...

51单片机-AT24C02(IIC总线介绍及其时序编写步骤)-第一节(下一节实战)

IIC开始通信(6大步) 我以前的文章也有对基本常用的通信协议讲解,如SPI UART IIC RS232 RS485 CAN的讲解,可前往主页查询,(2024.9.12,晚上20:53,将AT24C02存储芯片,掉电不…...

<<编码>> 第 11 章 逻辑门电路--或非门, 与非门, 缓冲器 示例电路

继电器或非门 info::操作说明 鼠标单击开关切换开合状态 闭合任意一个开关可使电路断开 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/code-hlchs-examples/assets/circuit/code-hlchs-ch11-19-nor-gate-by-relay.txt 或非门 i…...

股票api接口程序化报备,程序化交易监管对个人量化交易者有何影响

炒股自动化:申请官方API接口,散户也可以 python炒股自动化(0),申请券商API接口 python炒股自动化(1),量化交易接口区别 Python炒股自动化(2):获取…...

如何自己搭建一个网站?

今天的文章总结适合0基础,网站搭建的技巧和流程,哪怕你是小白,不会编程,也可以制作非常漂亮且实用的企业网站,如果想做个人博客更是不在话下。希望我的经验能帮助更多没有过多的经费、没有建站基础的朋友。用户跟着我的…...

虚拟化数据恢复—断电导致虚拟机目录项被破坏的数据恢复案例

虚拟化数据恢复环境: 某品牌服务器(部署VMware EXSI虚拟机)同品牌存储(存放虚拟机文件)。 虚拟化故障: 意外断电导致服务器上某台虚拟机无法正常启动。查看虚拟机配置文件发现这台故障虚拟机除了磁盘文件以…...

[机器学习]聚类算法

1 聚类算法简介 # 导包 from sklearn.datasets import make_blobs import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.metrics import calinski_harabasz_score # 构建数据 x,ymake_blobs(n_samples1000,n_features2,centers[[-1,-1],[0,0],[1…...

JVM面试真题总结(七)

文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 解释GC的引用计数算法及其局限性 引用计数算法是一种非常直观、简…...

深入理解CASAtomic原子操作类详解

1.CAS介绍 什么是 CAS CAS(Compare And Swap,比较与交换),是非阻塞同步的实现原理,它是CPU硬件层面的一种指令,从CPU层面能保证"比较与交换"两个操作的原子性。CAS指令操作包括三个参数&#x…...

C51单片机-单按键输入识别,键盘消抖

【实验目的】 独立按键的识别方法、键盘消抖等。 【实验现象】 每按一次独立键盘的S2键,与P1口相连的八个发光二极管中点亮的一个往下移动一位。 【实验说明】 关于按键去抖动的解释,我们在手动按键的时候,由于机械抖动或是其它一些非人为的因…...

基于CNN卷积神经网络迁移学习的图像识别实现

基于CNN卷积神经网络迁移学习的图像识别实现 基于CNN卷积神经网络迁移学习的图像识别实现写在前面一,原理介绍迁移学习的基本方法1.样本迁移(Instance based TL)2.特征迁移(Feature based TL)3.模型迁移(Pa…...

【iOS】push和present的区别

【iOS】push和present的区别 文章目录 【iOS】push和present的区别前言pushpop presentdismiss简单小demo来展示dismiss和presentdismiss多级 push和present的区别区别相同点 前言 在iOS开发中,我们经常性的会用到界面的一个切换的问题,这里我们需要理清…...

在Linux服务器上添加用户并设置自动登录

需要在Linux服务器上添加一个新用户,可以使用以下命令 # 这个命令会创建一个新的用户账户,默认情况下不会设置密码,不会在 /home 目录下为新用户创建home目录: # sudo useradd 用户名 # # 如果希望同时为新用户创建家目录&#…...

网站被爬,数据泄露,如何应对不断强化的安全危机?

近年来,众多传统零售商和互联网企业借助大数据、人工智能等先进技术手段,通过场景化设计、优化客户体验、融合线上线下渠道,推动了网络电商行业的消费方式变革,成为电商领域新的增长动力。 但值得注意的是,网络电商带来…...

为什么HTTPS会引入SSL/TLS协议

这时我面试遇到过的问题,整理了一下,希望对大家有帮助! 祝大家秋招顺利! 首先 SSL/TLS 协议通过使用数字证书来实现服务器身份认证, 当用户访问一个 HTTPS 网站时,浏览器会验证服务器的数字证书, 1.首先他对验证整证书是否在有效期 2.其次他会看证书中的服务器域名…...

Spring AOP,通知使用,spring事务管理,spring_web搭建

spring AOP AOP概述 AOP面向切面编程是对面向对象编程的延续(AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。) 面向切面编…...

PHP无缝对接预订无忧场馆预订系统小程序源码

无缝对接,预订无忧 —— 场馆预订系统,让每一次活动都完美启航! 一、告别繁琐流程,预订从未如此简单 你是否曾经为了预订一个合适的场馆而焦头烂额?繁琐的咨询、确认、支付流程,让人心力交瘁。但现在&…...

Unet改进30:添加CAA(2024最新改进方法)|上下文锚定注意模块来捕获远程上下文信息。

本文内容:在不同位置添加CAA注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 遥感图像中的目标检测经常面临一些日益严峻的挑战,包括目标尺度的巨大变化和不同的测距环境。先前的方法试图通过大核卷积或扩展卷积来扩展主干的空间感受野来解决这…...

OpenAI震撼发布最强模型o1!强化学习突破LLM推理极限

OpenAI新模型无预警上新: o1系列,可以进行通用复杂推理,每次回答要花费更长时间思考。 在解决博士水平的物理问题时,GPT-4o还是“不及格”59.5分,o1一跃来到“优秀档”,直接干到92.8分! 没错…...

速通GPT-2:Language Models are Unsupervised Multitask Learners全文解读

文章目录 GPT系列论文速通引言总览GPT和GPT-2区别Abstract1. 概括2. 具体分析 Introduction1. 概括2. 具体分析当前机器学习系统的局限性希望构建通用型系统数据集与任务通用性缺乏的原因 Approach1. 概括与要点2. 原文阅读翻译3. 具体分析论文核心Training DatasetInput Repre…...