MST

星途 面试题库

面试题:Go并发中使用互斥锁优化性能的高级技巧

在高并发场景下,使用互斥锁保护共享数据可能会成为性能瓶颈。请详细说明一些使用互斥锁优化性能的高级技巧,包括但不限于读写锁的合理运用、减少锁的粒度等,并通过具体的代码示例展示如何在实际项目中应用这些技巧来提升性能。
37.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

1. 读写锁的合理运用

  • 原理:读写锁允许多个线程同时进行读操作,但只允许一个线程进行写操作。当有写操作时,所有读操作和其他写操作都会被阻塞,这样可以保证数据的一致性,同时在读多写少的场景下能显著提升性能。
  • 示例(以Python为例)
import threading

class Data:
    def __init__(self):
        self.value = 0
        self.lock = threading.RLock()
        self.read_lock = threading.Semaphore(1)
        self.write_lock = threading.Semaphore(1)

    def read(self):
        self.read_lock.acquire()
        self.lock.acquire()
        try:
            return self.value
        finally:
            self.lock.release()
            self.read_lock.release()

    def write(self, new_value):
        self.write_lock.acquire()
        self.lock.acquire()
        try:
            self.value = new_value
        finally:
            self.lock.release()
            self.write_lock.release()


data = Data()

def reader_thread():
    for _ in range(1000):
        result = data.read()
        # 处理读取到的数据
        pass


def writer_thread():
    for _ in range(100):
        data.write(_)


readers = [threading.Thread(target=reader_thread) for _ in range(10)]
writers = [threading.Thread(target=writer_thread) for _ in range(2)]

for reader in readers:
    reader.start()
for writer in writers:
    writer.start()

for reader in readers:
    reader.join()
for writer in writers:
    writer.join()

2. 减少锁的粒度

  • 原理:将大的共享数据结构分解为多个小的部分,每个部分使用单独的锁进行保护。这样不同线程可以同时访问不同部分的数据,减少锁竞争。
  • 示例(以Java为例)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class FineGrainedLocking {
    private final Lock[] locks;
    private final int[] data;

    public FineGrainedLocking(int size) {
        locks = new Lock[size];
        data = new int[size];
        for (int i = 0; i < size; i++) {
            locks[i] = new ReentrantLock();
        }
    }

    public void update(int index, int value) {
        locks[index].lock();
        try {
            data[index] = value;
        } finally {
            locks[index].unlock();
        }
    }

    public int read(int index) {
        locks[index].lock();
        try {
            return data[index];
        } finally {
            locks[index].unlock();
        }
    }
}

3. 锁的分层

  • 原理:对于复杂的数据结构,可以采用锁分层的方式。例如,对于树形结构,可以对每个节点设置锁,并且父节点的锁可以覆盖子节点的锁。这样在进行某些操作时,可以只获取父节点的锁,而不是获取所有子节点的锁,从而减少锁的范围。
  • 示例(以C++为例,简单模拟树形结构锁分层)
#include <mutex>
#include <vector>

class TreeNode {
public:
    std::mutex nodeLock;
    std::vector<TreeNode*> children;
    int data;

    TreeNode(int value) : data(value) {}

    void updateData(int newData) {
        std::lock_guard<std::mutex> lock(nodeLock);
        data = newData;
    }

    int getData() {
        std::lock_guard<std::mutex> lock(nodeLock);
        return data;
    }
};

class Tree {
public:
    TreeNode* root;
    std::mutex rootLock;

    Tree(int rootValue) {
        root = new TreeNode(rootValue);
    }

    void updateRootData(int newData) {
        std::lock_guard<std::mutex> lock(rootLock);
        root->updateData(newData);
    }

    int getRootData() {
        std::lock_guard<std::mutex> lock(rootLock);
        return root->getData();
    }
};

4. 乐观锁

  • 原理:乐观锁假设在大多数情况下,线程不会发生冲突,因此在进行数据操作时,不会像互斥锁那样一开始就加锁。而是在更新数据的时候,检查数据在操作过程中是否被其他线程修改过,如果没有被修改过,则执行更新操作,否则重试。
  • 示例(以Python为例,使用版本号实现乐观锁)
class OptimisticLocking:
    def __init__(self):
        self.value = 0
        self.version = 0

    def update(self, new_value):
        while True:
            current_version = self.version
            current_value = self.value
            # 模拟业务逻辑
            new_result = current_value + new_value
            if self.version == current_version:
                self.value = new_result
                self.version += 1
                return