高性能编程:无锁队列

news2024/9/21 16:17:41

目录

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:队列为空时不阻塞消费者线程

6. MsgQueue:多生产者多消费者(MPMC)

7. MPSCQueue:多生产者单消费(MPSC)


1.无锁队列

无锁队列(Lock-Free Queue)是一种在多线程环境下,不使用传统的锁机制(如互斥锁、信号量)即可实现线程安全的队列数据结构。它主要依赖于原子操作(如CAS:Compare-And-Swap)来确保并发操作的正确性和一致性。

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

高性能编程:无锁队列----LockedQueue代码实践icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_43925427/article/details/142206860?fromshare=blogdetail&sharetype=blogdetail&sharerId=142206860&sharerefer=PC&sharesource=weixin_43925427&sharefrom=from_link

6. MsgQueue:多生产者多消费者(MPMC)

高性能编程:无锁队列----MsgQueue代码实践icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_43925427/article/details/142211304?fromshare=blogdetail&sharetype=blogdetail&sharerId=142211304&sharerefer=PC&sharesource=weixin_43925427&sharefrom=from_link

7. MPSCQueue:多生产者单消费(MPSC)

高性能编程:无锁队列----MPSCQueue代码实践icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_43925427/article/details/142258099?fromshare=blogdetail&sharetype=blogdetail&sharerId=142258099&sharerefer=PC&sharesource=weixin_43925427&sharefrom=from_link

参考:

 0voice · GitHub

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

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

相关文章

打破瓶颈:搭贝低代码平台助力企业数字化转型

在当今快速变化的商业环境中,越来越多的企业认识到数字化转型的重要性。然而,很多企业在追求数字化的过程中却遇到各种障碍,无论是信息管理的混乱、软件使用的低效,还是应对市场变化的迟缓,这些问题都在消耗企业的资源…

React学习笔记(1.0)

在使用vite创建react时,有一个语言选项,就是typescript-SWC,这里介绍一下SWC。 SWC:可扩展的Rust的平台,用于下一代快速开发工具,SWC比Babel快20倍。 简单来说,就是用于格式转换的&#xff0c…

反向沙箱的功能特点

在这个信息化飞速发展的时代,企业的数据安全面临着前所未有的挑战。员工的无意操作、恶意软件的潜伏、甚至是敌对势力的网络攻击,都可能成为企业数据安全的致命威胁。深信达SPN反向沙箱为您筑起了一道坚不可摧的数据安全防线! 来百度APP畅享高…

《Python青少年趣味编程108例》书籍介绍

文章目录 前言为什么选择Python?书籍介绍文章目录配套资源 前言 在这个数字化飞速发展的时代,编程已经成为了一项不可或缺的技能。对于青少年而言,学习编程不仅能够培养逻辑思维、解决问题的能力,还能激发无限创意,让…

代码随想录刷题day32丨动态规划理论基础,509. 斐波那契数, 70. 爬楼梯, 746. 使用最小花费爬楼梯

代码随想录刷题day32丨动态规划理论基础,509. 斐波那契数, 70. 爬楼梯, 746. 使用最小花费爬楼梯 1.动态规划理论基础 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题…

如何实现跨站点协同管理和异地远程管理监控?

前言 随着科技进步,企业愈发重视智能化生产,它提升效率、降低成本、提高质量,帮助企业更好应对市场变化。对于拥有多个分散站点的大型企业,跨站点协同管理成为一大挑战。 在这一背景下,宏集物联网HMI异地远程管理和监…

SSM 传统工艺品销售网站---附源码74714

摘 要 近年来,信息网络迅猛推进,其具有灵活方便、传递消息速度快等优点,这一新兴媒体日渐兴盛,已经成为人们日常生活获取信息一个重要手段。从08开始,电商行业如春风吹过后的小草,呈现出一片蓬勃地发展态势…

yjs03——matplotlib的介绍与使用(一个图里面画折线)

import...as plt plt.figure(figsize(宽度,高度),dpi清晰度) x... y... plt.plot(x,y,label"上海",color“r”,linestyle“--”) plt.xticks(刻度ticks(仅限数字)&#xf…

测试2sigma离群点过滤

椭圆跑道形内部的离群点移除失败,影响拟合结果

为什么自动驾驶技术的实现离不开4G+5G多卡聚合?

如今,汽车制造商和零部件巨头都在研究自动驾驶相关技术。要实现汽车的自动驾驶,不乏相关技术与道路环境的结合和变化。但要实现这一目标,最重要的环节无疑是建设网络。 在4G时代,随着网络带宽和速度的提高,可以实现实…

PMP--一模--解题--51-60

文章目录 9.资源管理--职能经理--项目经理要找他沟通51、 [单选] 团队成员必须按照进度基准来完成一个复杂项目的可交付成果。但是,由于一些团队成员被其他职能经理分配给其他任务,导致项目落后。 若要将项目拉回正轨,项目经理应该做什么&…

软件安装攻略:EmEditor编辑器下载安装与使用

EmEditor是一款在Windows平台上运行的文字编辑程序。EmEditor以运作轻巧、敏捷而又功能强大、丰富著称,得到许多用户的好评。Windows内建的记事本程式由于功能太过单薄,所以有不少用户直接以EmEditor取代,emeditor是一个跨平台的文本编辑器&a…

【vuetify】v-select 无法正常显示,踩坑记录!

一、上代码 template <v-selectv-model"editedUser.userRole":items"roles"label"角色"item-value"value":rules"[rules.required]" ></v-select>script const editedUser ref({userRole: customer // 设置…

springboot老年康复中心—计算机毕业设计源码27406

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出法&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤,采用Springboo框架建设老年康复中心信息管理系统。…

Redis运维之监控指标,性能监控,监控方式,响应慢分析

文章目录 1 Redis监控1.1 Redis监控指标1.1.1 性能指标: Performance1.1.2 内存指标: Memory1.1.3 基本活动指标&#xff1a;Basic activity1.1.4 持久性指标: Persistence1.1.5 错误指标&#xff1a;Error 1.2 监控方式1.2.1 info1.2.2 性能监控1.2.3 内存监控1.2.4 基本活动指…

警惕!尿血背后隐藏的健康危机,你不可不知的五大原因!

在这个快节奏的时代&#xff0c;健康成为了我们最宝贵的财富。然而&#xff0c;一些细微的身体信号往往被忽视&#xff0c;直到问题严重才引起重视。今天&#xff0c;我们就来聊聊一个让人不安却又必须正视的话题——尿血。当你发现尿液中混杂着红色或粉红色时&#xff0c;这不…

攻防演练篇:攻防演练场景中面临的常见加密威胁-HTTP隐蔽隧道

1 概述 在网络安全领域&#xff0c;隐蔽隧道是一种基于主流常规协议将恶意流量伪装成正常通信起到夹带偷传数据、下发控制指令等作用&#xff0c;同时对数据进行加密以最大限度的规避网络安全设备检测的传输技术。由于隐蔽隧道更容易绕过网络安全设备的检测&#xff0c;因此黑…

unity安装配置和vs2022联动教程

目录 1.选择vs2022配置 2.安装unity 2.1安装unity hub 2.2注册个人账号 2.3安装编辑器 2.4修改为简体中文 2.5添加许可证 2.6安装位置修改 3.项目的创建 3.1如何创建 3.2如何选择 3.3配置语言 3.4去哪里找语言包 4.unity编辑器窗口的介绍 4.1游戏的运行和停止 4…

某讯/企鹅滑块验证码逆向(一)

文章目录 免责声明前言请求分析collect参数 总结 免责声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由…

C++竞赛初阶L1-15-第六单元-多维数组(34~35课)556: T456506 矩阵转置

题目内容 输入一个 n 行 m 列的矩阵 A,输出它的转置 AT。 输入格式 第一行包含两个整数 n 和 m,表示矩阵 A 的行数和列数。1≤n≤100,1≤m≤100。 接下来 n 行,每行 m 个整数,表示矩阵 A 的元素。相邻两个整数之间用单个空格隔开,每个元素均在 1∼1000 之间。 输出格…