面试题答案
一键面试性能问题分析
- 锁竞争:多个线程同时访问任务队列时,频繁获取和释放互斥锁会导致锁竞争,线程等待锁的时间增加,降低整体效率。
- 线程阻塞:当某个线程持有锁时,其他线程需要等待,可能造成线程长时间阻塞,无法及时处理任务。
- 上下文切换:频繁的线程阻塞和唤醒会导致大量的上下文切换开销,消耗系统资源。
优化方案
- 减少锁粒度
- 方案描述:将任务队列按照一定规则(如任务类型、任务ID等)进行划分,每个子队列使用单独的互斥锁。这样不同线程可以同时访问不同子队列,减少锁竞争。
- C语言代码示例:
#include <pthread.h>
#include <stdio.h>
#define QUEUE_SIZE 10
#define SUB_QUEUE_COUNT 2
typedef struct {
int data[QUEUE_SIZE];
int head;
int tail;
pthread_mutex_t lock;
} SubQueue;
typedef struct {
SubQueue subQueues[SUB_QUEUE_COUNT];
} TaskQueue;
TaskQueue taskQueue;
void initTaskQueue() {
for (int i = 0; i < SUB_QUEUE_COUNT; i++) {
taskQueue.subQueues[i].head = 0;
taskQueue.subQueues[i].tail = 0;
pthread_mutex_init(&taskQueue.subQueues[i].lock, NULL);
}
}
void enqueue(int task, int subQueueIndex) {
if (subQueueIndex < 0 || subQueueIndex >= SUB_QUEUE_COUNT) {
return;
}
pthread_mutex_lock(&taskQueue.subQueues[subQueueIndex].lock);
taskQueue.subQueues[subQueueIndex].data[taskQueue.subQueues[subQueueIndex].tail] = task;
taskQueue.subQueues[subQueueIndex].tail = (taskQueue.subQueues[subQueueIndex].tail + 1) % QUEUE_SIZE;
pthread_mutex_unlock(&taskQueue.subQueues[subQueueIndex].lock);
}
int dequeue(int subQueueIndex) {
if (subQueueIndex < 0 || subQueueIndex >= SUB_QUEUE_COUNT) {
return -1;
}
pthread_mutex_lock(&taskQueue.subQueues[subQueueIndex].lock);
if (taskQueue.subQueues[subQueueIndex].head == taskQueue.subQueues[subQueueIndex].tail) {
pthread_mutex_unlock(&taskQueue.subQueues[subQueueIndex].lock);
return -1;
}
int task = taskQueue.subQueues[subQueueIndex].data[taskQueue.subQueues[subQueueIndex].head];
taskQueue.subQueues[subQueueIndex].head = (taskQueue.subQueues[subQueueIndex].head + 1) % QUEUE_SIZE;
pthread_mutex_unlock(&taskQueue.subQueues[subQueueIndex].lock);
return task;
}
- **优缺点**:
- **优点**:在高并发且任务分布较为均匀的情况下,能显著减少锁竞争,提高性能。因为不同线程可以并行处理不同子队列的任务。
- **缺点**:如果任务分布不均匀,某个子队列可能会成为热点,仍然存在锁竞争问题。同时,管理多个锁增加了代码复杂度。
2. 无锁数据结构 - 方案描述:使用无锁数据结构,如无锁队列(如基于CAS操作实现的队列)。无锁数据结构允许线程在不使用锁的情况下安全地访问和修改数据,避免锁竞争。 - C语言代码示例:(简单模拟基于CAS的无锁队列)
#include <pthread.h>
#include <stdio.h>
#include <stdatomic.h>
#define QUEUE_SIZE 10
typedef struct {
atomic_int head;
atomic_int tail;
int data[QUEUE_SIZE];
} LockFreeQueue;
LockFreeQueue lockFreeQueue;
void initLockFreeQueue() {
atomic_store(&lockFreeQueue.head, 0);
atomic_store(&lockFreeQueue.tail, 0);
}
int enqueueLockFree(int task) {
int tail = atomic_load(&lockFreeQueue.tail);
int nextTail = (tail + 1) % QUEUE_SIZE;
if (nextTail == atomic_load(&lockFreeQueue.head)) {
return 0; // 队列满
}
lockFreeQueue.data[tail] = task;
atomic_store(&lockFreeQueue.tail, nextTail);
return 1;
}
int dequeueLockFree() {
int head = atomic_load(&lockFreeQueue.head);
if (head == atomic_load(&lockFreeQueue.tail)) {
return -1; // 队列为空
}
int task = lockFreeQueue.data[head];
atomic_store(&lockFreeQueue.head, (head + 1) % QUEUE_SIZE);
return task;
}
- **优缺点**:
- **优点**:在高并发场景下,能提供极高的性能,避免了锁竞争和线程阻塞带来的开销。适用于对性能要求极高的场景。
- **缺点**:实现复杂,调试困难。无锁数据结构通常依赖底层原子操作,代码可读性较差。并且在某些情况下,可能会因为频繁的CAS重试导致CPU资源浪费。