MST

星途 面试题库

面试题:Go语言原子操作与锁机制在复杂并发场景的对比

在一个需要频繁读写共享数据的复杂并发场景中,什么时候优先选择原子操作而不是锁机制来提高并发能力?请举例说明,并阐述原子操作在这种场景下相较于锁机制的优势和局限性。
28.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

优先选择原子操作的场景

  1. 简单数据操作:当对共享数据的操作仅仅是简单的读取、写入或者简单的算术运算(如自增、自减)时,优先选择原子操作。例如,在多线程环境下统计网站的访问量,只需要对一个计数器变量进行原子的自增操作。
  2. 低竞争场景:如果并发访问共享数据的线程数量相对较少,竞争不激烈,原子操作能以较小的开销保证数据一致性,此时适合原子操作。

举例说明

以统计网站访问量为例,假设有多个线程同时处理用户请求,每次有请求到达,需要对一个共享的计数器变量 count 进行加1操作。使用原子操作如下(以C++为例):

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> count(0);

void increment() {
    for (int i = 0; i < 1000; ++i) {
        count.fetch_add(1, std::memory_order_relaxed);
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final count: " << count.load() << std::endl;
    return 0;
}

原子操作相较于锁机制的优势

  1. 性能优势:原子操作在硬件层面实现,开销小,不需要像锁那样进行上下文切换等昂贵操作。在低竞争场景下,能极大提高并发性能。
  2. 简单易用:原子操作的接口简单,通常是直接对变量进行操作,不需要像锁机制那样,需要仔细管理锁的获取和释放,减少了死锁等风险。

原子操作的局限性

  1. 功能局限:原子操作只能保证单个操作的原子性,对于复杂的操作序列(如先读取数据,根据数据再进行复杂计算然后写入),原子操作无法保证整个序列的原子性,此时仍需要锁机制。
  2. 同步语义局限:原子操作的内存模型相对复杂,不同的原子操作内存序(如 std::memory_order_relaxedstd::memory_order_seq_cst 等)有不同的语义,使用不当可能导致数据一致性问题,而锁机制在这方面相对直观。