1 multiprocessing模块
Python中的多线程无法利用多核优势,如果想要充分利用多核CPU的资源,大部分情况需要使用多进程。
multiprocessing模块可以用来开启子进程,并且提供了许多功能组件,Process,Lock,Queue,Pipe。
2 Process的用法
开启子进程的2种方式
from multiprocessing import Process
import time
def task1(name):
print("%s 开始执行" % name)
time.sleep(3)
print("%s 执行完毕" % name)
if __name__ == '__main__':
proc=Process(target=task1, args=("进程1",)) #target表示调用对象,及需要执行的任务,注意函数不要加括号,args(元组)表示调用对象的位置参数,还可以加kwargs来通过字典的方式传参
proc.start() # start方法只是向操作系统发出请求信号,请求操作系统开启一个进程
print("hahah")
from multiprocessing import Process
import time
class MyProcess(Process): # 继承Process
def __init__(self,name):
super().__init__() # 必须调用父类Process的init方法进行初始化,不然会报错
self.name = name
def run(self): # 进程启动时运行的方法,通过此方法调用需要执行的target对应的函数
print("%s is runing" % self.name)
time.sleep(3)
print("%s is done" % self.name)
if __name__ == "__main__":
p = MyProcess("子进程")
p.start() # 启动进程,并调用进程中的run()方法
print("主进程")
查看子进程id和主进程id
from multiprocessing import Process
import time
import os
def task(name,n):
print("%s is runing " % (name,))
print("this process id:",os.getpid())
print("father process id:", os.getppid())
print("%s is done" % name)
if __name__ == "__main__":
p = Process(target=task,args=("jack",1),name="子进程1") # name:为进程取的名字
p.start()
print("main process id :",os.getpid()) # 在当前进程中开启一个子进程p,即p是该进程的子进程,所以此处的pid与进程p中的ppid是相同的
main process id : 8148
jack is runing
this process id: 5760
father process id: 8148
jack is done
join的用法
在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况
1:主进程的任务与子进程的任务相互独立,互不干扰,主进程的任务先执行完后,还需要等待子进程执行完毕,然后统一回收资源。
2:如果主进程的任务执行到一半时,需要等待子进程执行完毕后才能继续执行后面的任务,就需要有一种机制能够让主进程检测子进程是否运行完毕,在子进程执行完毕后才继续执行,否则一直在原地阻塞,这时就需要join了
from multiprocessing import Process
import time
import os
def talk(name,n):
print("%s is talking " % (name,))
time.sleep(n)
print("%s is done" % name)
if __name__ == "__main__":
stime = time.time()
p1 = Process(target=talk,args=("p1",1))
p2 = Process(target=talk, args=("p2", 2))
p3 = Process(target=talk, args=("p3", 3))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
etime = time.time()
print(etime-stime)
p1 is talking
p2 is talking
p3 is talking
p1 is done
p2 is done
p3 is done
3.3871939182281494
from multiprocessing import Process
import time
import os
def talk(name,n):
print("%s is talking " % (name,))
time.sleep(n)
print("%s is done" % name)
if __name__ == "__main__":
stime = time.time()
for i in range(1,4):
p = Process(target=talk,args=("p"+str(i),i))
p.start()
p.join()
etime = time.time()
print(etime-stime)
p1 is talking
p1 is done
p2 is talking
p2 is done
p3 is talking
p3 is done
6.675381660461426
通过上面2个例子,我们可以看出
我们可以通过join方法让主进程等待子进程,直到子进程执行完毕后,再接着执行主进程。注意:是让主进程等待子进程 ,而不是让其他的子进程等待。join([timeout])可以传入一个超时参数,即主进程的等待时间。如果超过该等待时间主进程就不会在等子进程了。
当我们开启一个进程,马上join时,主进程会等该进程执行完毕后再开启下一个进程,这样就变成了串行。
守护进程
守护进程就如字面意思一样,就是守护主进程的,当主进程执行完毕后,守护进程无论时候执行完,都会立即结束。就好比古时候的太监一样,平时辅助皇帝,当皇帝驾崩后,太监也要跟着陪葬。
关于守护进程需要注意2个点:
1 守护进程需要在start()前设置
2 守护进程不能创建子进程
from multiprocessing import Process
import time
import os
def talk(name,n):
print("%s is talking " % (name,))
time.sleep(n)
print("%s is done" % name)
if __name__ == "__main__":
p = Process(target=talk,args=("p",10))
p.daemon = True # 通过p.daemon = True 设置守护进程
p.start()
time.sleep(1)
print("主")
由于p为守护进程,故主进程执行完毕后,p也跟着结束了。所以只输出了p is talking ,而p is done还没来得及输出
p is talking
主
is_alive()和terminate()
在程序运行的时候,我们可以查看进程是否仍在运行,也可以强制结束进程。
from multiprocessing import Process
import time
def talk(name,n):
print("%s is talking " % (name,))
time.sleep(n)
print("%s is done" % name)
if __name__ == "__main__":
stime = time.time()
p = Process(target=talk,args=("p",10))
p.start() #start方法只是向操作系统发出请求信号,请求操作系统开启一个进程
print(p.is_alive()) # 如果执行速度够快,此时进程可能还没有开启,这里可能返回False也可能返回True
time.sleep(2)
print(p.is_alive()) # 经过2秒后操作系统肯定已经开启进程了故此处为True
time.sleep(2)
p.terminate() # 强制结束进程
etime = time.time()
print(etime-stime)
执行结果,由于经过2次time.sleep(2)后,将子进程p强制结束了,故程序执行时间最后只有4秒,而没有10秒
True
p is talking
True
4.023230314254761