本文共 5763 字,大约阅读时间需要 19 分钟。
由于GIL的存在,python中的多线程并不是真正的多线程。
如果想要充分的使用多核CPU的资源,在python中大部分情况需要使用多进程。
在计算机中,进程与进程这之间在内存中是相互独立的,是两块完全不同的内存空间,而且相互之间没有任何联系。
在线程之中,在全局定义一个变量,所有的线程都是共用的,但是不同的进程之间的数据则不是公有的。
multiprocessing包是python中的多进程管理包。
与threading.Thread类似,myltiprocessing模块可以利用multiprocessing.Process对象来创建一个子进程。
multiprocessing的很大一部分用法与threading使用同一套API。
Process对象与Thread对象的用法相同,也有start(),run()和join()的方法。
此外multiprocessing包中也有Lock,Event,Smaphore,Condition类,这些对象可以像多线程那样,通过参数传递给各个进程,以实现同步进程。
大家在用chrome浏览器浏览网页的时候,打开任务管理器,会看到chrome的进程会不止一个,那么怎么在在一段py程序里面开辟一个子进程呢??
python中子进程的创建有两种方法:
import multiprocessingimport timedef func(): print("hello world------>",time.ctime()) time.sleep(2) #让系统休眠2S print("func ending------>",time.ctime())if __name__ == "__main__": p1=multiprocessing.Process(target=func,args=()) #实例化一个进程 p1.start() #启动进程 print("ending------>",time.ctime()) #计算程序执行所花费的时间
这样就创建一个进程,如果电脑的CPU是多核的话,这两个程序就会并行执行。
执行程序,程序最后一句"ending"和"hello world"会同进打印在屏幕上,然后程序休眠2s,又会在屏幕上打印一句"func ending",程序执行结束。
在程序执行期间,打开任务管理器,会看到进程列表中有两个python.exe的进程,等到程序执行完成,这两个python.exe的进程又会消失。
程序执行结果:ending------> Thu Jul 20 15:56:17 2017hello world------> Thu Jul 20 15:56:17 2017func ending------> Thu Jul 20 15:56:19 2017
from multiprocessing import Processimport timeclass MyProcess(Process): #定义一个类,这个类继承multiprocessing.Process这个类 def __init__(self,i): super(MyProcess,self).__init__() self.i=i def run(self): print("%s hello python------>"%self.i,time.ctime()) time.sleep(2)if __name__=="__main__": p_list=[] for i in range(3): p1=MyProcess(i) #实例化进程 p1.start() #启动进程 p_list.append(p1) for item in p_list: item.join() #阻塞主进程,全子进程执行完毕再执行主进程 print("ending------>",time.ctime()) #计算程序执行所花费的时间
利用类的继承,创建了3个进程,这三个进程同时在屏幕在打印自身的编号及一句话,然后程序休眠2s后,又会打印结束话语。
在程序的执行过程中,查看系统进程列表,会看到python解释器的进程编号:
E:\py_code>tasklist | findstr pythonpython.exe 5760 Console 1 11,524 Kpython.exe 3488 Console 1 11,616 Kpython.exe 6900 Console 1 11,672 Kpython.exe 4384 Console 1 11,636 K
程序执行结果:
1 hello python------> Thu Jul 20 16:05:07 20172 hello python------> Thu Jul 20 16:05:07 20170 hello python------> Thu Jul 20 16:05:07 2017ending------> Thu Jul 20 16:05:09 2017
来看下面的例子:
让系统执行一段范围内的累加和累乘操作,计算CPU执行这两个操作所花的时间。 第一种方式:正常的定义两个函数,然后执行程序。def func1(x): res1=0 for i in range(x): res1 += i #累加计算的结果 return res1def func2(y): res2=1 for i in range(1,y): res2 *= i #累乘计算的结果 return res2s1=time.time()func1(100000000) #执行累加函数func2(100000) #执行累乘函数s2=time.time()print("cost time:%s"%(s2-s1)) #计算程序执行所花费的时间
程序返回结果:
cost time:9.273045301437378
第二种方式,使用程序执行另外两个进程,分别调用系统资源来运算,计算CPU所花费的时间。
from multiprocessing import Processimport timedef func1(x): res1=0 for i in range(x): res1 += i return res1def func2(y): res2=1 for i in range(1,y): res2 *= i return res2if __name__=="__main__": t1=time.time() p1=Process(target=func1,args=(100000000,)) #实例化进程p1 p1.start() #启动进程p1 p2=Process(target=func2,args=(100000,)) #实例化进程p2 p2.start() #启动进程pp2 p1.join() p2.join() print("ending") t2=time.time() print("cost time:%s"%(t2-t1)) #计算程序运行所花费的时间
执行程序,查看系统的任务管理器,可以看到程序在运行的过程中,生成了三个进程。
E:\py_code>tasklist | findstr pythonpython.exe 6520 Console 1 11,536 Kpython.exe 4340 Console 1 11,612 Kpython.exe 6200 Console 1 12,240 K
程序执行结果:
endingcost time:5.437908697128296
可以看到,第二段代码里面有三个进程(一个主进程和两个子进程p1,p2),
同时在执行这两个函数,所以CPU在执行这两个运行的时候所花的时间会少一些的原因。
优点: 可以利用多核,以实现并形运算 缺点: 1.浪费的系统资源比较多 2.进程之间的通信比较困难
在系统的提示符下,导入multiprocessing模块,使用:
import multiprocessing
查看这个模块的内置的方法:
help(multiprocessing.Process)
multiprocessing.Process内置方法:构造方法: group 线程组 target 要执行的方法 name 进程的名 args/kwargs 执行过程中要传入的参数 实例方法: is_alive() 测试进程是否在运行 join([timeout]) 阻塞当前上下文环境的进程,直到调用此方法的进程终止或到达指定的timeout start() 进程准备就绪,等待CPU调度 run() start()调用run方法,如果实例进程未制定传入target时,这start执行默认的run()方法 terminate() 不管任务是否完成,立即停止工作进程 属性: deamon 和线程的setDeamon功能一样 name 进程的名字 pid(ident) 进程号 ppid 进程的父进程号
Process内置方法的用法:
代码如下:from multiprocessing import Processimport osimport timedef info(name): print("process name:",name) #打印当前进程的进程名 print("parent process:",os.getppid()) #打印当前进程的父进程ID号 print("process:",os.getpid()) #打印当前进程的进程ID号 print("---------") time.sleep(10)def foo(name): info(name)if __name__=="__main__": info("main process") p1=Process(target=info,args=("process1",)) p1.start() p1.join() p2=Process(target=foo,args=("process2",)) p2.start() p2.join() print("ending")
程序执行过程中,打开系统的任务管理器,查找python的进程可以看到:
E:\py_code>tasklist | findstr pythonpython.exe 2424 Console 1 11,536 Kpython.exe 5360 Console 1 11,632 Kpython.exe 2532 Console 1 11,664 K
执行程序,返回结果如下:
process name: main process lineparent process: 628process: 2424--------- process name: process1parent process: 2424process: 2532---------process name: process2parent process: 2424process: 5360---------ending
可以看到process1和process2的进程名和进程号,这两个进程的父进程号都是一样的,都是主进程的进程号。
需要注意的是,python的进程之间的切换,耗费的系统资源比线程的切换耗费的资源多得多。
转载地址:http://cbrfa.baihongyu.com/