面试题答案
一键面试性能优化方面
- 线程调度
- 使用线程池:创建一个固定大小的线程池,避免频繁创建和销毁线程的开销。例如,在初始化阶段,预先创建一定数量的线程并将它们放入线程池中等待任务。
- 设置线程优先级:根据任务的紧急程度设置线程优先级。例如,对于网络通信相关的线程(处理实时数据传输)设置较高优先级,而对于一些非紧急的业务逻辑计算线程设置较低优先级。在Linux下可以使用
pthread_setschedparam
函数来设置线程优先级。
- 资源分配
- 内存池:对于频繁申请和释放内存的场景(如处理客户端请求的缓冲区),使用内存池技术。预先分配一块较大的内存,然后从这块内存中分配小块内存供线程使用,当线程使用完毕后归还到内存池中,避免频繁的系统调用
malloc
和free
。 - 文件描述符管理:对于磁盘I/O操作,合理分配文件描述符。可以采用复用文件描述符的方式,避免过多的文件描述符打开导致系统资源耗尽。例如,使用
epoll
(在Linux下)来管理多个文件描述符,高效地处理I/O事件。
- 内存池:对于频繁申请和释放内存的场景(如处理客户端请求的缓冲区),使用内存池技术。预先分配一块较大的内存,然后从这块内存中分配小块内存供线程使用,当线程使用完毕后归还到内存池中,避免频繁的系统调用
- 缓存机制
- 数据缓存:对于经常访问的数据(如配置信息、热点数据等),使用缓存。可以采用哈希表等数据结构来实现缓存,提高数据访问速度。例如,将常用的业务逻辑计算结果缓存起来,当下次相同请求到来时,直接从缓存中获取结果,减少重复计算。
- I/O缓存:在磁盘I/O和网络通信中使用缓冲区。例如,在读取磁盘文件时,使用较大的缓冲区一次性读取较多数据,减少磁盘I/O次数;在网络通信中,使用发送缓冲区和接收缓冲区来提高数据传输效率。
- 异步I/O
- 磁盘I/O异步化:在Linux下,可以使用
aio
系列函数(如aio_read
、aio_write
)实现异步磁盘I/O。这样主线程不会阻塞等待磁盘I/O完成,可以继续处理其他任务。例如,当一个线程发起异步磁盘I/O请求后,主线程可以继续处理新的客户端请求,当I/O操作完成后,通过回调函数或事件通知机制来处理结果。 - 网络异步I/O:使用异步网络I/O模型,如
epoll
的边缘触发模式(ET)结合非阻塞套接字。在这种模式下,当有数据到达时,系统只会通知一次,应用程序需要尽快处理数据,避免数据丢失。这样可以在高并发情况下更高效地处理网络请求。
- 磁盘I/O异步化:在Linux下,可以使用
同步机制设计
- 设计思路
- 条件变量:用于线程间的同步,当某个条件满足时,等待该条件的线程被唤醒。在部分请求需要等待其他请求完成的场景下,当被依赖的请求完成时,通过条件变量通知等待的线程。
- 信号量:可以用来控制对共享资源的访问数量。在这种场景下,可以使用信号量来控制依赖关系,例如,当一个请求完成后,释放一个信号量,等待的请求获取这个信号量后继续执行。
- 关键代码片段
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
// 定义条件变量和互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 定义信号量
sem_t sem;
// 全局变量,用于标记请求是否完成
int request_completed = 0;
// 被依赖的请求处理函数
void* dependent_request(void* arg) {
// 模拟业务逻辑计算
printf("Dependent request is processing...\n");
// 完成业务逻辑后
pthread_mutex_lock(&mutex);
request_completed = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sem_post(&sem);
pthread_exit(NULL);
}
// 依赖其他请求的请求处理函数
void* dependent_on_request(void* arg) {
pthread_mutex_lock(&mutex);
while (!request_completed) {
pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);
sem_wait(&sem);
// 继续处理依赖后的业务逻辑
printf("Request that depends on others is continuing...\n");
pthread_exit(NULL);
}
int main() {
pthread_t tid1, tid2;
sem_init(&sem, 0, 0);
// 创建线程
pthread_create(&tid1, NULL, dependent_request, NULL);
pthread_create(&tid2, NULL, dependent_on_request, NULL);
// 等待线程结束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
在上述代码中:
pthread_cond_t
类型的cond
是条件变量,pthread_mutex_t
类型的mutex
是互斥锁,用于保护共享资源request_completed
。sem_t
类型的sem
是信号量。dependent_request
函数模拟被依赖的请求,当它完成时,通过条件变量cond
通知等待的线程,并释放信号量。dependent_on_request
函数模拟依赖其他请求的请求,它通过条件变量等待request_completed
变为1,并获取信号量后继续执行后续业务逻辑。