在上一篇中介绍了进程、线程、线程池的概念后,本篇我们再进一步,看看并发产生时操作系统是如何执行的,
以及并发给编程带来哪些和传统编程不一样的问题。
一、并发(Concurrency)
定义:同时做多件事情。
解释:比如GUI程序中用户输入数据时同时对数据做处理;WEB服务器同时处理多个用户请求等。这里同时指
的是一个时间区间,而不是一个时间点。
二、多线程(Multithreading)
从操作系统的角度来说,多线程是一个时间段内有多个线程在运行,这多个线程可以属于同一个进程也可以属于
不同的进程。
从编程的角度来说,多线程特指某个进程内有1个以上的线程在CPU上执行指令, 在这多个线程中,有一个是主线程,
其他的线程是由主线程创建的子线程,多线程是并发的微观表现形式。
三、多线程的2种运行情况。
第一种:单核CPU
CPU的执行是分时间片来进行的。
在单核CPU的情况下,操作系统会分配一定的CPU时间片给线程去执行指令,线程在使用完时间片后被挂起,系统再将
CPU时间片分配给下一个线程,每个时间片依次轮流地执行处理各个应用程序的线程指令,由于单个时间片很短,相对于
一个应用程序来说,就好像是处理器在为自己单独服务一样,从而达到多个应用程序在同时运行的效果。
系统中的多个线程是如何被选中去使用CPU时间片的呢?是根据线程的优先级由操作系统的调度算法来对线程进行调度的。
一般线程的优先级由两部分决定:自身在进程中的相对优先级和所属进程的优先级。
既然单核CPU在某个时间片内只能执行一个线程的指令,因此,要想我们的应用程序获得更快的执行速度,在所有线程
优先级相同的情况下,理论上应用程序就应该开启多个线程来增加被CPU执行的次数。从而提高运行速度,这是我们进行
多线程编程的出发点。
注:实际情况不一定如此,因为即使优先级相同,线程的创建、启动、切换、相互间的通讯、同步、回收、销毁等都是
有时间开销的,所以在单核CPU的情况下,如果没有I/O等耗时操作,应用程序使用多线程并不一定运行更快,这个要特别注意。
单核CPU的结构如下图:
第二种:多核CPU
(1)多核的 "核" 究竟指的是什么
CPU的主频越高运行越快,但是主频的增长不可能无极限的,在这种情况下,要获得更快的计算速度和更低的功耗,
芯片设计者开始绕过主频,转而在一块CPU中增加多个核心(Core),这里的核心就是指 运算单元+寄存器。
(2)多核CPU的运行
在多核CPU的情况下,一个CPU有多个处理核心(即多个逻辑处理器,如下图,笔者的电脑就有12个),操作系统可以
将多个线程分别发送到不同的逻辑处理器去运行,让线程的执行做到真正的并行(Parallel)。
(3)多核CPU的调度
多核CPU的任务调度算法有全局队列调度和局部队列调度。
全局队列调度:操作系统维护一个全局的任务等待队列,当系统中有一个CPU核心空闲时,操作系统就从全局任务等待队列中
选取就绪任务开始在此核心上执行。这种算法的优点是CPU核心利用率较高。
局部队列调度:操作系统为每个CPU内核维护一个局部的任务等待队列,当系统中有一个CPU内核空闲时,便从该核心的任务
等待队列中选取恰当的任务执行,这种方法的优点是任务基本上无需在多个CPU核心间切换,有利于提高CPU核心局部Cache命中率。
目前多数多核CPU操作系统采用的是基于全局队列的任务调度算法。
四、并发带来的问题
不管是单核CPU还是多核CPU,在进行并发编程时都会产生下面的问题
1. 数据一致性
2. 上下文切换
并发编程就是在利用多线程好处的时候处理好它带来的种种问题。