多线程一定会让程序运行更快吗?
创建线程的问题,上下文切换的问题,死锁的问题,硬件和软件资源的问题
上下文切换
即使单核的CPU也是支持多线程执行代码的,CPU给每个线程分配时间片来实现这个机制。
时间片是CPU分配给各个线程的时间,非常短,所以CPU通过不停的切换线程执行,时间片一般是几十毫秒。
CPU通过时间片分配算法来执行任务
- 使用Lmbench3可以测量上下文切换的时长
- 使用vmstat可以测量上下文切换的次数
CS表示上下文切换的次数
减少上下文切换
- 无锁并发编程
多线程竞争锁时会引起上下文切换,所以多线程处理数据时可以避免锁,如将数据的ID按照Hash算法取模分段。 - CAS算法
Java的Atomic包使用CAS算法来更新数据,不需要加锁。 - 使用最少线程
避免创建不需要的线程。 - 协程
在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
死锁
锁是非常有用的工具,运用场景非常丰富,但是可能会引起死锁,造成系统功能不可用。
- 避免一个线程同时获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
资源限制的挑战
程序运行速度受限与计算机硬件资源和软件资源。比如说服务器的网络带宽时固定了,即使并发也不可能超过这个阀值;另外还有磁盘的读写,CPU的处理速度等。
并发编程中,将代码程序加快的原则是将代码中串行执行的变成并发执行,但是如果受限于资源,仍然是串行执行的,那程序不仅不会加快,反而会变慢。
对于硬件资源,可以采用集群并行执行程序,如ODPS,Hadoop等