多进程相关内容
multiprocessing模块与process类
multiprocessing
python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。
process类
参数介绍:
group参数未使用,值始终为Nonetarget表示调用对象,即子进程要执行的任务args表示调用对象的位置参数元组,args=(1,2,'egon',)kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}name为子进程的名称
方法介绍:
p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁p.is_alive():如果p仍然运行,返回Truep.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
属性介绍:
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置p.name:进程的名称p.pid:进程的pidp.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
创建子进程的两种方式
注意:在windows中Process()必须放到# if name == 'main':下
第一种方式:
from multiprocessing import Process
import time
def task(name):print(f"{name} is running")time.sleep(3)print(f"{name} is gone")
if __name__ == '__main__':p = Process(target = task,args=('黑哥',)) # 创建一个进程对象# p = Process(target=task,kwargs={'name':'黑哥'}) 两种传参方式p.start() # 只是向操作系统发出一个开辟子进程的信号,然后就执行下一行了.# 这个信号操作系统接收到之后,会从内存中开辟一个子进程空间,然后在将主进程所有数据copy加载到子进程,然后在调用cpu去执行.# 开辟子进程开销是很大的.print('==主')# 所以永远会先执行主进程的代码.
# 结果:
==主
黑哥 is running
黑哥 is gone
第二种方式:
from multiuprocessing import Process
import timeclass MyProcess(Process):def __init__(self,name):super().__init__()self.name = namedef run(self): # 必须定义一个run方法print(f"{self.name} is runing")time.sleep(2)print(f"{self.name} is gone")
if __name__ == "__main__":p = MyProcess('黑哥')p.start()print('==主')
# 结果:
==主
黑哥 is running
黑哥 is gone
简单应用:
from multiprocessing import Process
import time
def task(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")def task1(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")
def task2(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")
if __name__ == '__main__':p1 = Process(target=task,args=('黑哥',))p2 = Process(target=task,args=('李业',))start_time = time.time()
# task('黑哥')
# task1('李业')
# task2('海狗')
# print(f"结束时间{time.time() - start_time}")p1.start() # 使用多进程优化代码运行时间p2.start() task('海狗')print(f"结束时间{time.time()-start_time}")
进程pid
如何获取内存中的所有进程?
- 命令行获取所有的进程的pid tasklist
代码级别如果获取一个进程pid
import os
print(os.getpid())
如何获取父进程(主进程)的pid?
import osimport time
print(f'子进程:{os.getpid()}')
print(f'主(父)进程:{os.getppid()}')
验证进程之间的空间隔离
在同一进程中:
x = 1000
def task():global xx = 2
task()
print(x)
# 结果:
2
在不同进程中:
from multiprocessing import Process
import time
x = 1000
def task():global xx = 2if __name__ == '__main__':p = Process(target=task)p.start()time.sleep(3)print(x)
# 结果:
1000
进程对象的join方法
join让主进程等待子进程结束之后,在执行主进程.
from multiprocessing import Process
import time
def task(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")if __name__ == '__main__':p = Process(target=task,args=('黑哥',))p.start()p.join()print("==主")
多个子进程使用join
from multiprocessing import Process
import timedef task(name,sec):print(f"{name} is running")time.sleep(sec)print(f"{name} is gone")if __name__ == '__main__':start_time = time.time()p1 = Process(target=task,args=('黑哥',1))p2 = Process(target=task,args=('李业',2))p3 = Process(target=task,args=('海狗',3))p1.start()p2.start()p3.start()p1.join()p2.join()p3.join()print(f"==主{time.time()-start_time}")
# 结果:
李业 is running
黑哥 is running
海狗 is running
黑哥 is gone
李业 is gone
海狗 is gone
==主3.6357808113098145
from multiprocessing import Process
import time
def task(name,sec):print(f'{name} is running')time.sleep(sec)print(f"{name} is gone")
if __name__ == '__main__':start_time = time.time()p1 = Process(target=task,args=('黑哥',3))p2 = Process(target=task,args=('李业',2))p3 = Process(target=task,args=('海狗',4))p1.start()p2.start()p3.start()p1.join()print(f"==主1:{time.time()-start_time}")p2.join()print(f"==主2:{time.time()-start_time}")p3.join()print(f"==主3:{time.time()-start_time}")
# 结果:
黑哥 is running
海狗 is running
李业 is running
李业 is gone
黑哥 is gone
==主1:3.741270065307617
==主2:3.741270065307617
海狗 is gone
==主3:4.746762990951538
相关面试题:
# 优化下面的代码:
from multiprocessing import Process
import timedef task(sec):print(f'is running')time.sleep(sec)print(f' is gone')if __name__ == '__main__':start_time = time.time()p1 = Process(target=task,args=(1,))p2 = Process(target=task,args=(2,))p3 = Process(target=task,args=(3,))p1.start()p2.start()p3.start()# join 只针对主进程,如果join下面多次join 他是不阻塞的.p1.join()p2.join()p3.join()# 正确解法:
from multiprocessing import Process
import timedef task(sec):print(f"is running")time.sleep(sec)print(f"is gone")if __name__ == '__main__':p1 = Process(target=task,args=('常鑫',3))p2 = Process(target=task,args=('立业',2))p3 = Process(target=task,args=('还够',4))start_time = time.time()p1.start()p2.start()p3.start()lst = []for i in range(1,4):p = Process(target=task,args = (i,))p.start()lst.append(p)for i in lst:i.join()print(f"{i}", f'{time.time() - start_time}')
进程对象的其他属性
from multiprocessing import Process
import timedef task(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")if __name__ == '__main__':# p = Process(target=task,args=('黑哥',))p = Process(target=task,args=('黑哥',),name='alex')p.start()time.sleep(1)p.terminate() # 杀死子进程p.join()time.sleep(0.5)print(p.is_alive()) # 判断进程是否存在print(p.name)p.name = 'sb' # 给子进程起名字print(p.name)print('==主开始')
守护进程
子进程守护着主进程,只要主进程结束,子进程跟着就结束,
主进程创建守护进程
其一:守护进程会在主进程代码执行结束后就终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止
import time
def task(name):print(f"{name} is running")time.sleep(2)print(f"{name} is gone")if __name__ == '__main__':p = Process(target=task,args=('黑哥',))p.daemon = True # 一定要在子进程开启之前设置p.start()time.sleep(1)print('==主')
# 结果:
黑哥 is running
==主