面试题答案
一键面试1. 线程创建与销毁开销
- 分析:频繁创建和销毁线程会带来较大开销,因为创建线程涉及分配内存、初始化线程控制块等操作,销毁线程也有资源清理等工作。
- 优化措施:
- 线程池:提前创建一定数量的线程放入线程池,任务来时从线程池中获取线程执行,执行完任务后线程不销毁而是返回线程池等待下一个任务。这样避免了反复创建和销毁线程的开销。
- 减少不必要线程操作:评估是否真的需要频繁创建和销毁线程,优化业务逻辑,尽量复用已有的线程。
2. 资源竞争
- 分析:多个线程同时访问共享资源(如全局变量、文件描述符等)时,会产生资源竞争,导致线程等待锁,降低调度性能。
- 优化措施:
- 锁优化:
- 选择合适的锁:如果读操作多写操作少,可使用读写锁(如
pthread_rwlock
),允许多个线程同时读;对于一般情况,使用互斥锁(pthread_mutex
)。并且要注意锁的粒度,尽量减小锁的保护范围,只在访问共享资源时加锁。 - 减少锁持有时间:在临界区内只放置必要的代码,尽快完成对共享资源的操作并释放锁。
- 选择合适的锁:如果读操作多写操作少,可使用读写锁(如
- 无锁数据结构:使用无锁数据结构(如无锁队列、无锁哈希表等),这些数据结构通过原子操作实现线程安全,避免了锁竞争,但实现较复杂。
- 锁优化:
3. 线程调度策略
- 分析:不合适的线程调度策略会导致某些线程长时间得不到执行,影响整体性能。Linux下默认的调度策略是SCHED_OTHER,还有SCHED_FIFO、SCHED_RR等。
- 优化措施:
- 调整调度策略:根据应用场景选择合适的调度策略。例如对于实时性要求高的任务,可选择SCHED_FIFO或SCHED_RR策略,但要注意使用这些策略可能会导致低优先级线程饥饿,需合理设置线程优先级。
- 设置合适的优先级:通过
pthread_setschedparam
函数设置线程的优先级,让重要的任务得到优先执行。
4. 线程数量
- 分析:线程数量过多可能导致上下文切换频繁,消耗大量CPU时间;线程数量过少则无法充分利用多核CPU资源。
- 优化措施:
- 动态调整线程数量:根据系统资源(如CPU核心数、内存等)和任务负载动态调整线程数量。例如,可使用监控工具获取系统当前负载信息,当负载较低时增加线程数量以提高处理能力,负载过高时减少线程数量避免过度竞争。
- 线程亲和性:将线程绑定到特定的CPU核心上,减少跨核心的上下文切换开销,提高性能。可以使用
pthread_setaffinity_np
函数实现线程亲和性设置。
5. 同步机制开销
- 分析:除了锁之外,其他同步机制(如条件变量
pthread_cond
、信号量sem_t
)也可能带来开销。例如,条件变量的等待和唤醒操作,信号量的P、V操作等。 - 优化措施:
- 减少不必要的同步:仔细分析同步需求,去除不必要的同步操作,避免过度同步导致的性能损耗。
- 优化同步代码:在使用同步机制时,确保代码逻辑正确且高效。例如,在使用条件变量时,要注意避免虚假唤醒,并且合理设置等待条件。