目录
1、理解什么是CPU密集型与IO密集型
1.1 CPU密集型
概念解释
策略
1.2 I/O密集型
概念解释
策略
2、《Java并发编程实践》:具体的线程数该如何设置?线程池参数如何设置?
参数解释
3、总结
即,计算密集型,I/O能够在很短的时间内完成,而相对的CPU却有大量运算要处理。例如计算大量的加减乘除、矩阵运算等,都属于CPU密集型。
我们知道,线程是最小的可执行单位。
严格来说,每个核心在同一时间只能处理一条线程的指令,因此如果是单核CPU的情况下,创建再多的线程其实也不会加快运算速度,反而会因为单核的线程并发导致线程上下文的切换而降低效率。(类似于一个工人干了多个活)
而在多核cpu下,可以创建多个线程让多个cpu并行运算,一起工作。(多个工人同时做多个活),从而提升效率。
IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,但CPU的使用率不高。
在实际开发中,IO密集型任务也很常见,例如:
磁盘IO:读写本地的数据库、Redis,等。网络IO:http 请求、远程数据库读写、远程 Redis 读写,等
这里需要解释一下,什么叫“CPU在等I/O (硬盘/内存) 的读/写操作”?
在传统的阻塞式 I/O 操作模型中,当 CPU 发起一个 I/O 请求后,发起该操作的线程会一直阻塞等待 I/O 操作的完成:
当线程发起一个阻塞式的 IO 操作时,它会等待操作完成,期间线程将被挂起,无法继续执行其他指令,这种模型导致了CPU的使用率不高。需要注意的是,IO 阻塞并不是直接阻塞 CPU 的执行,而是阻塞了发起 IO 操作的线程。其他未受影响的线程仍然可以继续执行。
在上面的基础上我们知道,在处理IO密集型任务,即使创建了线程,也可能因为IO的阻塞等待而让线程阻塞、从而导致CPU不干活一直摸鱼
为了不让cpu偷偷休息,可以增加更多的线程,当一个线程或进程在等待某个 I/O 操作完成时,其他线程或进程可以继续执行其他任务,减少了 CPU 空闲时间,这是可以通过线程池实现的复用技术。
结论:Ncpu 表示 核心数,线程数设置规则如下
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 Ncpu+1
如果是IO密集型任务,参考值可以设置为 2 * Ncpu
对于cpu密集型,之所以为Ncpu+1,因为:
“计算密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个“额外”的线程,可以确保在这种情况下CPU周期不会中断工作。”
对于IO密集型,假设所有线程都被阻塞,有Ncp个空闲CPU,因此可以再多给一样数量的线程数,因此为2倍Ncpu
实际上,有这样的计算公式:
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
实际上,CPU密集型如果卡顿,往往是因为cpu不够用;IO密集型卡顿往往是因为线程不够用。