标签:开启 get ref cname library 布尔值 程序员 traceback 指南
multiprocessing
是一个使用类似于threading
模块的API支持生成进程的包。该multiprocessing
软件包提供本地和远程并发。因此,该multiprocessing
模块允许程序员充分利用给定机器上的多个处理器。可以在Unix和Windows上运行。
Process
(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)应该始终使用关键字参数调用构造函数
threading.Thread
join
([timeout])join可防止产生僵尸进程,文档中的编程指南中指出: 每次开启一个新进程,所有未被join的进程会被join(也就是说非守护进程会自动被join),但即便如此也要明确地join启动的所有进程。 因此如果不手动地join子线程,主进程也会等待子进程中止之后再中止
【另外join会影响守护进程的行为,后面探讨】
# -*- coding:utf-8 -*- import os from multiprocessing import Process def func(name): print(‘%s进程%d,父进程%d‘ % (name, os.getpid(), os.getppid())) ‘‘‘ 在Windows中,Process开启进程会再次导入此文件,为防止导入时再次执行,需要添加 if __name__ == ‘__main__‘: ‘‘‘ if __name__ == ‘__main__‘: func(‘主‘) p = Process(target=func, args=[‘子‘]) p.start() p.join()
结果:
主进程16452,父进程21852
子进程28472,父进程16452
如果子类重写构造函数,则必须确保它在对进程执行任何其他操作之前调用构造函数 [Process.__init__() ]。
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os class InheritTest(Process): def __init__(self, name): super().__init__() self.name = name def run(self): print(‘我是子进程%s,进程id=%d,父进程id=%d‘ % (self.name, os.getpid(), os.getppid())) time.sleep(2) if __name__ == ‘__main__‘: print(‘我是主进程, 进程id=%d,父进程id=%d‘ % (os.getpid(), os.getppid())) p = InheritTest(‘小明‘) p.start() p.join()
结果:
我是主进程, 进程id=18408,父进程id=21852
我是子进程小明,进程id=22640,父进程id=18408
若多个进程被join,阻塞时长是他们(包括主进程在这期间的执行时间)中执行时间最长的
# -*- coding:utf-8 -*- from multiprocessing import Process import time def short_time(): print(‘进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) time.sleep(2) def long_time(): print(‘进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) time.sleep(4) if __name__ == "__main__": p1 = Process(target=long_time) p2 = Process(target=short_time) p3 = Process(target=short_time) p4 = Process(target=short_time) p1.start() p2.start() p3.start() p4.start() print(‘1号进程阻塞中‘) p1.join() print(‘2号进程阻塞中‘) p2.join() print(‘3号进程阻塞中‘) p3.join() print(‘4号进程阻塞中‘) p4.join() ‘‘‘ p1-p4异步执行,p1执行时间最长,那么p1.join()阻塞完后,其它进程已经执行完了, p2-p4.join()不阻塞,直接执行 ‘‘‘
结果:
1号进程阻塞中
进程pid=26404,ppid=17928
进程pid=17960,ppid=17928
进程pid=15592,ppid=17928
进程pid=8724,ppid=17928
2号进程阻塞中
3号进程阻塞中
4号进程阻塞中
问1:只能在父进程中join子进程吗?
问1的解释: 在子进程中join其它同级的子进程会抛出异常 AssertionError: can only join a child process,因此只能在父进程中join子进程:
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os def func1(): time.sleep(2) print(‘func1 进程pid={} ppid={}‘.format(os.getpid(), os.getppid())) def func2(p1): p1.join() print(‘func2 进程pid={} ppid={}‘.format(os.getpid(), os.getppid())) if __name__ == "__main__": print(‘主进程id {}‘.format(os.getpid())) p1 = Process(target=func1) p2 = Process(target=func2, args=[p1]) p2.start() # 和下面代码互换会报另一个异常 p1.start()
主进程id 14796
Process Process-2:
Traceback (most recent call last):
...............
AssertionError: can only join a child process
func1 进程pid=30100 ppid=14796
【单独调用run不会开启子进程】
start()
方法返回到子进程终止的那一刻,进程对象处于活动状态。
None
。
# -*- coding:utf-8 -*- import os from multiprocessing import Process import time def func(name): print(‘%s进程%d,父进程%d‘ % (name, os.getpid(), os.getppid())) if name != ‘主‘: time.sleep(2) if __name__ == ‘__main__‘: func(‘主‘) p = Process(target=func, args=[‘子‘]) p.start() print(‘p.pid()‘, p.pid) print(‘p.is_alive()=‘, p.is_alive()) print(‘p.exitcode=‘, p.exitcode) p.join() print(‘p.exitcode=‘, p.exitcode) print(‘p.is_alive()=‘, p.is_alive())
结果
主进程1548,父进程21852
p.pid() 24000
p.is_alive()= True
p.exitcode= None
子进程24000,父进程1548
p.exitcode= 0
p.is_alive()= False
daemon
start()
调用之前设置 它。
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os def daemon_func(): time.sleep(2) print(‘守护进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) if __name__ == "__main__": print(‘主进程id {}‘.format(os.getpid())) p = Process(target=daemon_func) p.daemon = True p.start() # p.join()
当p.join()注释后,主进程中止,守护进程也中止,因此输出:
主进程id 15096
若取消注释,守护进程被join,主进程会等待此守护进程,输出为:
主进程id 10896
守护进程pid=19404,ppid=10896
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守护进程p1执行 def daemon_func(): time.sleep(1) print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) # 非守护进程p2执行 def non_daemon_func(): time.sleep(2) print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) if __name__ == "__main__": print(‘主进程id {}‘.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start()
主进程执行完立即中止守护进程(主进程此时自己没中止),主进程等待非守护进程,然后中止
因此执行结果是:
主进程id 24588
non_daemon_func 进程pid=3772,ppid=24588 ### 这里ppid是24588,而不是1,说明主进程还未中止
(4.1)守护进程被join:
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守护进程p1执行 def daemon_func(): time.sleep(1) print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) # 非守护进程p2执行 def non_daemon_func(): time.sleep(2) print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) if __name__ == "__main__": print(‘主进程id {}‘.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start() p1.join() # join守护进程
主进程执行完后没中止守护进程,并等待非守护进程执行完:
主进程id 24416
daemon_func 进程pid=27312,ppid=24416
non_daemon_func 进程pid=12408,ppid=24416
守护进程睡三秒,主进程仍会等待守护进程执行完:
主进程id 20336
non_daemon_func 进程pid=24528,ppid=20336
daemon_func 进程pid=16596,ppid=20336
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守护进程p1执行 def daemon_func(): time.sleep(1) print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) # 非守护进程p2执行 def non_daemon_func(): time.sleep(2) print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid())) if __name__ == "__main__": print(‘主进程id {}‘.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start() p2.join() # join非守护进程
非守护进程被join,主进程等待非守护进程,非守护进程中止后,立即中止守护进程。
------------------------------------------------------------------------------
注意【1.主进程只join非守护进程】和【2.主进程没有join任何进程】的区别:
1: 主进程会被join阻塞,等到非守护进程中止后,中止守护进程
2: 主进程执行完立即中止守护进程,若非守护进程未中止,等待
其实都是主进程的代码执行完毕后,才中止子守护进程,只是1包含了手动join进程的代码,阻塞后代码才算执行完毕。
-----------------------------------------------------------------
守护进程睡1秒后,非守护进程还在睡,主进程被阻塞住,因此守护进程有输出
主进程id 11284
daemon_func 进程pid=5308,ppid=11284
non_daemon_func 进程pid=30364,ppid=11284
守护进程睡3秒后,非守护进程在2秒时睡醒后中止,主进程便在此时中止守护进程,因此守护进程没有输出
主进程id 24912
non_daemon_func 进程pid=19892,ppid=24912
join在很多地方都有用到,预知join的行为并合理利用join,避免产生死锁
中止进程,在Unix上是用SIGTERM信号完成的;在Windows上,使用TerminateProcess();
注意,退出处理程序和finally子句等不会被执行
被中止进程的子进程不会被中止
避免使用此方法:使用该方法停止进程可能导致进程当前使用的任何共享资源被破坏或不可用于其它进程,最好只考虑该方法用在从不使用共享资源的进程上
参考:
如有意见或建议,一起交流;如有侵权,请告知删除。
python多进程——multiprocessing.Process
标签:开启 get ref cname library 布尔值 程序员 traceback 指南
原文地址:https://www.cnblogs.com/Magic-Dev/p/11420692.html