多核、多线程、多进程及Python通过multiprocessing和threading实现多线程多进程

1、多核、多线程、多进程定义

1.1CPU

CPU:叫做微处理器,微处理器由一片或少数几片大规模集成电路组成的中央处理器,这些电路执行控制部件和算数逻辑部件的功能。微处理器能完成取指令,执行指令,(我们写的程序,不论是java语言还是c语言最终都会编译成机器指令进行相应的运算)以及与外界存储器和逻辑部件交换信息等操作,是微型计算机的运算控制部分,他可与存储器和外围电路芯片组成微型计算机。CPU是运行机器指令和与存储等逻辑部件交换信息的东西。

CPU主要分为两部分 1 执行部件:执行计算机指令的部分;2 总线接口部件:与计算机总线联系,执行从存储器取指令的操作。执行部件有一个寄存器堆:由8个16位的寄存器组成,用于存放数据,变址,和堆栈指针,算数运算逻辑单元执行算术运算和逻辑操作。内部总线:用来连接微处理器的各功能部件并传送微处理器内部的数据和控制信号。存储器:微型计算机的存储器用来存放当前正在使用的或经常使用的程序和数据,存储器按读,写方式分为随机存储器RAM和只读存储器ROM。RAM 也称为读写存储器,工作过程中CPU可根据需要随时对其内容进行读和写操作,RAM的内容断电后全部丢失,ROM只能读出不能写入,断电后可以保存。单核就是CPU集成了一个运算核心; 双核是两个运算核心,相当于两个CPU同时工作; 四核是四个运算核心,相当于四个CPU同时工作。 完成同样的任务,由一条生产线来完成或由两条稍慢的生产线来完成或由四条更慢的生产线来完成,虽然生产线的生产速度慢,但由于同时进行的生产线多,所以任务的最终完成时间可能最短。 一般来看,如果经常运行大型软件或游戏,或经常进行图形设计,尽量采用多核处理器,可以有效提高处理速度。

1.2多道程序设计    

在进程执行过程中常常会因为资源请求或者IO被阻塞或中断(有的请求或者中断需要处理很长时间),此时CPU便空闲出来,众所周知,CPU是计算机中非常宝贵的资源,为提高其利用率,操作系统需通过进程切换,将CPU交给就绪队列的某个进程使用;等上次被阻塞或者中端的进程再次满足执行条件(一般是请求的资源得到满足或者IO完成等)后,操作系统便通过调度算法将CPU再次交给该进程执行任务,其中操作系统的进程调度算法有多种(例如在交互式系统(windows)中的进程调度算法有时间片轮转调度、优先级调度、多级队列调度等,这些相信大家都很熟悉了,此处不再进一步阐述),具体选择依赖操作系统。这时从用户的角度感觉是多个进程在同时执行,这的易于操作系统通过进程调度将一个cpu变成多个虚拟的CPU,实现多个进程的伪并发。在《现在操作系统》中将这种进程间的切换称之为“多道程序设计”。(注:每个进程在执行过程中表现了不同的形态,CPU需要根据进程执行过程中的特性制定CPU调度算法从而提高CPU利用率)(注:CPU的并发需求产生了进程,进程执行过程中的特性产生了CPU调度算法,CPU调度时需要维护每个进程特有的数据和空间,因此产生了维护每个进程的进程表项)

1.3多核与多个CPU的区别


何为多核CPU?我们将多个核心装载一个封装里,让用户理解成这是一个处理器。这样好处就是原本运行在单机跑的程序基本不需要更改就能够获得非常不错的性能。多核心发展趋势也是英特尔一直坚持的方式。

何为多个CPU运行呢?了解服务器的人都知道有单路,双路,多路之分,而ARM针对服务器市场推出的处理器也是呈现这种方式,最终能够形成分布式系统,其实跟多核CPU内部的分布式结果是一样的,只不过那个从外部看是单个处理器。

例如,你需要搬很多砖,你现在有一百只手。当你将这一百只手全安装到一个人身上,这模式就是多核。当你将这一百之手安装到50个人身上工作,这模式就是多CPU。那么多核跟多CPU在应用中有什么区别呢?首先我们看多核的模式,就是一个人身上安一百个手的方式,这个即使这个人再笨,干活速度也要比只有两只手的人要快。 但是将一百只手放在一个人身上,同样会带来一些问题,例如一百只手搬砖太多了,这样身体的脊柱就受不了了,就会顶不住。这就是CPU的多核的极限。于是,当搬砖数量较多的时候,多CPU的方式就显现出来了。人多力量大呀。多核CPU在发展上如今已经遇到了瓶颈,没法支撑这么多核。多CPU的方式被称为分布式计算,简单理解就是多台相连的计算机各自承担同一工作任务的不同部分,在人的控制下,同时运行,共同完成一件工作任务。用“人多力量大”这句话可以很好的形容分布式的计算模式,多个处理器调节好了,能够提供很好的计算效率,同时这种方式的价格更便宜。

1.4进程

一个程序的执行实例就是一个进程。每一个进程提供执行程序所需的所有资源。(进程本质上是资源的集合)

一个进程有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间),还要有至少一个线程。

每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。

1.5线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时恢复到当时读的具体进度。有一个方法就是记下页数、行数与字数这三个数值,这些数值就是execution context。如果你的室友在你休息的时候,使用相同的方法读这本书。你和她只需要这三个数字记下来就可以在交替的时间共同阅读这本书了。线程的工作方式与此类似。CPU会给你一个在同一时间能够做多个运算的幻觉,实际上它在每个运算上只花了极少的时间,本质上CPU同一时刻只干了一件事。它能这样做就是因为它有每个运算的execution context。就像你能够和你朋友共享同一本书一样,多任务也能共享同一块CPU。

多线程与并行计算的区别
(1)多线程的作用不只是用作并行计算,还在单核时代,多线程就广泛应用,这时候多线程大多用于降低阻塞带来的CPU资源闲置,注意这里没有浪费CPU资源,去掉sleep(1)就是纯浪费了。
while(1)
{
if(flag==1)
break; 
sleep(1);
}
阻塞在什么时候发生呢?一般是等待IO操作(磁盘,数据库,网络等等)。此时如果单线程,CPU会干转不干实事(与本程序无关的事情都算不干实事,因为执行其他程序对我来说没意义),效率低下(针对这个程序而言),例如一个IO操作要耗时10毫秒,CPU就会被阻塞接近10毫秒,这是何等的浪费啊!要知道CPU是数着纳秒过日子的。
所以这种耗时的IO操作就用一个线程Thread去代为执行,创建这个线程的函数(代码)部分不会被IO操作阻塞,继续干这个进程中其他的事情,而不是干等待(或者去执行其他程序)。
同样在这个单核时代,多线程的这个消除阻塞的作用还可以叫做“并发”,这和并行是有着本质的不同的。并发是“伪并行”,看似并行,而实际上还是一个CPU在执行一切事物,只是切换的太快,我们没法察觉罢了。例如基于UI的程序(俗话说就是图形界面),如果你点一个按钮触发的事件需要执行10秒钟,那么这个程序就会假死,因为程序在忙着执行,没空搭理用户的其他操作;而如果你把这个按钮触发的函数赋给一个线程,然后启动线程去执行,那么程序就不会假死,继续相应用户的其他操作。但是,随之而来的就是线程的互斥和同步、死锁等问题。
现在是多核时代了,这种线程的互斥和同步问题是更加严峻的,单核时代大都算并发,多核时代真的就大为不同,以前volatile型变量的使用可以解决大部分问题,(volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。他对其他线程是可见的。)例如多个线程共同访问一个Flag标志位,如果是单核并发,基本不会出问题(P.S.在什么情况下会出问题呢?Flag有多个,或者是一个数组,这时候只能通过逻辑手段搞定这个问题了,多来几次空转无所谓,别出致命问题就行),因为CPU只有一个,同时访问这个标志位的只能有一个线程,而多核情况下就不太一样了,同时访问这个标志位的可能有多个线程。所以仅仅volatile不太能解决问题,这就要用到具体语言,具体环境中的“信号量”了,Mutex,Monitor,Lock等等,这些类都操作了硬件上的“关中断”,达到“原语”效果,对临界区的访问不被打断的效果。
(2)并行计算还可以通过其他手段来获得,而多线程只是其中之一。
其他手段包括:多进程(这又包括共享存储区的和分布式多机,以及混合式的),指令级并行。
ILP(指令级并行),x86架构里叫SMT(同时多线程),在MIPS架构里与之对应的是super scalar(超标量)和乱序执行,二者有区别,但共同点都是可以达到指令级并行,这是用户没法控制的,不属于编程范围,只能做些有限的优化,而这有限的优化可能只属于编译器管辖的范畴,用户能做的甚少。
(3)典型的适于并行计算的语言
Erlang和MPI:这两个前者是语言,后者是C++和Fortran的扩展库,效果是一样的,利用多进程实现并行计算,Erlang是共享存储区的,MPI是混合型的。
C#.NET4.0:新版本4.0可以用少量代码实现并行For循环,
CUDA
3.线程越多越好吗?什么时候才有必要用多线程?
线程必然不是越多越好,线程切换也是要开销的,当你增加一个线程的时候,增加的额外开销要小于该线程能够消除的阻塞时间,这才叫物有所值。
Linux自从2.6内核开始,就会把不同的线程交给不同的核心去处理。Windows也从NT.4.0开始支持这一特性。
什么时候该使用多线程呢?这要分四种情况讨论:
a.多核CPU——计算密集型任务。此时要尽量使用多线程,可以提高任务执行效率,例如加密解密,数据压缩解压缩(视频、音频、普通数据),否则只能使一个核心满载,而其他核心闲置。
b.单核CPU——计算密集型任务。此时的任务已经把CPU资源100%消耗了,就没必要也不可能使用多线程来提高计算效率了;相反,如果要做人机交互,最好还是要用多线程,避免用户没法对计算机进行操作。
c.单核CPU——IO密集型任务,使用多线程还是为了人机交互方便,
d.多核CPU——IO密集型任务,这就更不用说了,跟单核时候原因一样。

1.6进程与线程区别

  • 同一个进程中的线程共享同一内存空间,但是进程之间是独立的。
  • 同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。
  • 对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
  • 线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
  • 同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。
  • 创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
  • 一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
  • 线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

2、multiprocessing

 

3、threading

4、比较

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值