def pstart(arg): var = 0 for i in xrange(100000000): var += 1 if __name__ == '__main__': p1 = Process(target = pstart, args = ("1", )) p2 = Process(target = pstart, args = ("2", )) start_time = time.time() p1.start() p2.start() p1.join() p2.join() print("Two process cost time: %s" % (time.time() - start_time)) start_time = time.time() pstart("0") print("Current process cost time: %s" % (time.time() - start_time))
结果:
Two process cost time: 2.91599988937 Current process cost time: 2.52400016785
对比分析
双进程并行执行和单进程执行相同的运算代码,耗时基本相同,双进程耗时会稍微多一些,可能的原因是进程创建和销毁会进行系统调用,造成额外的时间开销。
但是对于python线程,双线程并行执行耗时比单线程要高的多,效率相差近10倍。如果将两个并行线程改成串行执行,即:
t1.start() t1.join() t2.start() t2.join() #Two thread cost time: 5.12199997902 #Main thread cost time: 2.54200005531
可以看到三个线程串行执行,每一个执行的时间基本相同。
本质原因双线程是并发执行的,而不是真正的并行执行。原因就在于GIL锁。
GIL锁
提起python多线程就不得不提一下GIL(Global Interpreter Lock 全局解释器锁),这是目前占统治地位的python解释器CPython中为了保证数据安全所实现的一种锁。不管进程中有多少线程,只有拿到了GIL锁的线程才可以在CPU上运行,即时是多核处理器。对一个进程而言,不管有多少线程,任一时刻,只会有一个线程在执行。对于CPU密集型的线程,其效率不仅仅不高,反而有可能比较低。python多线程比较适用于IO密集型的程序。对于的确需要并行运行的程序,可以考虑多进程。
多线程对锁的争夺,CPU对线程的调度,线程之间的切换等均会有时间开销。
线程与进程区别下面简单的比较一下线程与进程
进程是资源分配的基本单位,线程是CPU执行和调度的基本单位;
通信/同步方式:
进程:
通信方式:管道,FIFO,消息队列,信号,共享内存,socket,stream流;
同步方式:PV信号量,管程
线程:
同步方式:互斥锁,递归锁,条件变量,信号量
通信方式:位于同一进程的线程共享进程资源,因此线程间没有类似于进程间用于数据传递的通信方式,线程间的通信主要是用于线程同步。
CPU上真正执行的是线程,线程比进程轻量,其切换和调度代价比进程要小;
线程间对于共享的进程数据需要考虑线程安全问题,由于进程之间是隔离的,拥有独立的内存空间资源,相对比较安全,只能通过上面列出的IPC(Inter-Process Communication)进行数据传输;
系统有一个个进程组成,每个进程包含代码段、数据段、堆空间和栈空间,以及操作系统共享部分 ,有等待,就绪和运行三种状态;
一个进程可以包含多个线程,线程之间共享进程的资源(文件描述符、全局变量、堆空间等),寄存器变量和栈空间等是线程私有的;
操作系统中一个进程挂掉不会影响其他进程,如果一个进程中的某个线程挂掉而且OS对线程的支持是多对一模型,那么会导致当前进程挂掉;
如果CPU和系统支持多线程与多进程,多个进程并行执行的同时,每个进程中的线程也可以并行执行,这样才能最大限度的榨取硬件的性能;
线程和进程的上下文切换进程切换过程切换牵涉到非常多的东西,寄存器内容保存到任务状态段TSS,切换页表,堆栈等。简单来说可以分为下面两步:
页全局目录切换,使CPU到新进程的线性地址空间寻址;
切换内核态堆栈和硬件上下文,硬件上下文包含CPU寄存器的内容,存放在TSS中;
线程运行于进程地址空间,切换过程不涉及到空间的变换,只牵涉到第二步;
使用多线程还是多进程?CPU密集型:程序需要占用CPU进行大量的运算和数据处理;
I/O密集型:程序中需要频繁的进行I/O操作;例如网络中socket数据传输和读取等;
由于python多线程并不是并行执行,因此较适合与I/O密集型程序,多进程并行执行适用于CPU密集型程序;
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx