目录
多线程程序也不一定好,具体问题具体分析。
IO密集型
(程序里面指令的执行,涉及一些IO操作,比如设备、文件、网络操作(等待客户端的连接IO操作是可以把程序阻塞住的)-》给这些程序分配CPU时间片的话,CPU相当于空闲下来了,资源浪费)
就绪队列和阻塞队列:
就绪队列是指处于等待 CPU 执行的进程的队列,这些进程已经满足了所有的执行条件,只需要等待 CPU 的分配。操作系统会按照一定的调度算法从就绪队列中选取一个进程分配 CPU 时间片。
阻塞队列是指因为等待某个事件的发生而被阻塞的进程的队列,例如等待某个 I/O 操作完成、等待某个信号量的释放等。这些进程不能被 CPU 执行,直到事件完成并进程被唤醒,进入就绪队列等待 CPU 分配时间片。
在操作系统中,进程会在就绪队列和阻塞队列之间不断切换,直到完成所有的任务。操作系统会根据进程的状态,将其从就绪队列或阻塞队列中移动到另一个队列中,以保证系统的正常运行。
无论是CPU单核、CPU多核、多CPU,都是比较适合多线程程序的.
CPU密集型
(程序里面的指令都是做计算用的)
CPU单核 一个线程就足以完成,多线程存在上下文切换,是额外的花销,线程越多上下文切换所花费的额外时间也越多,倒不如一个线 程一直进 行计算。
CPU多核、多CPU 多个线程可以并行执行,对CPU利用率好。
总结:对于CPU多核来说,无论是IO密集型还是CPU密集型都是适合设置为多线程的
线程池中线程数量确定:
为了完成任务,创建很多的线程可以吗?线程真的是越多越好?
线程的创建和销毁都是非常"重"的操作;
线程栈本身占用大量内存,线程函数存放的空间(每一个线程都需要线程栈)
线程的上下文切换要占用大量时间(CPUl利用率低)
大量线程同时唤醒会使系统经常出现锯齿状负载或者瞬间负载量很大导致宕机(同一时间很多IO操作准备好了)
创建一个线程,操作系统做的工作:
1. 用户状态切换到内核状态,空间的切换;
2. 分配线程栈空间,存放运行状态和局部变量信息;
3. 设置线程的上下文环境,程序计数器、寄存器、栈指针;
4. 维护线程调度,根据线程优先级和调度算法,决定哪个线程能够运行;
5. 分配CPU时间片;
6. 管理线程同步,避免线程之间的竞争条件和死锁等问题
7 . 线程执行过程中出现的异常和中断等情况;
8. 回收线程资源;
调整这个线程池中线程数量主要目的地是为了充分合理的使用CPU和内存资源,从而最大限度的提高程序的性能。
如果是CPU密集型任务,尽量压榨CPU,设置位Ncpu+1 ,(+1 是保证当线程由于页缺失故障(操作系统)或其它原因 导致暂停时,额外的这个线程就能顶上去,保证CPU 时钟周期不被浪费)
如果是IO密集型任务,参考值可以设置为 2 * NcpuIO的处理一般较慢,多于cores数的线程将为CPU争取更多的任务,不至在线程处理IO的过程造成CPU空闲导致资源浪费
线程池:
线程池的优势就是, 不会在任务执行的过程中执行线程的创建和销毁。在服务进程启动之初,就事先创建好线程池里面的线程,当业务流量到来时需要分配线程,直接从线程池中获取一个空闲线程执行task任务即可,task执行 完成后,也不用释放线程,而是把线程归还到线程池中继续给后续的task提供服务。
fixed模式线程池
线程池里面的线程个数是固定不变的,一般是ThreadPool创建时根据当前机器的CPU核心数量进行指 定。
cached模式线程池
线程池里面的线程个数是可动态增长的,根据任务的数量动态的增加线程的数量,但是会设置一个线程数量的阈值(线程过多的坏处上面已经讲过了)及就是说设置一个最大线程数量,任务处理完成,如果动态增长的线程空闲了60s还没 有处理其它任务,那么关闭线程就是说设置一个最大超时时间,保持池中最初数量的线程即可。